Skip to content
This repository has been archived by the owner on May 17, 2019. It is now read-only.

Date objects do not survive across node and browser boundaries. #171

Open
chrisgervang opened this issue Oct 25, 2018 · 3 comments
Open

Comments

@chrisgervang
Copy link

chrisgervang commented Oct 25, 2018

In fusion js the redux store is stringified and parsed to be passed between client and server. This creates an issue where high level types, including built-in's like Date break on this line:

preloadedState = JSON.parse(unescape(stateElement.textContent));

Normal parse doesn't work correctly for ISO8601 date strings, and there is a good example of a workaround I'll reference from here and a robust regex from here

// Problem
const body = `{
    "date": "2016-04-26T18:09:16Z"
}`;

const obj = JSON.parse(body);

const { date } = obj;
console.log(typeof date);
// "string"

But we can add a revive function that fixes this issue.

// Solution

function isIso8601(value: string): boolean {
  const dateFormat = /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/;
  return dateFormat.test(value)
}


function reviver(key, value) {
    if (typeof value === "string" && isIso8601(value)) {
        return new Date(value);
    }

    return value;
}

const text = '{ "date": "2016-04-26T18:09:16Z" }';
const obj = JSON.parse(text, reviver);

console.log(typeof obj.date);
// "object"

I'd like to open a PR to implement this reviver.

@mlmorg
Copy link

mlmorg commented Nov 1, 2018

This is something we've discussed and created an RFC for here: fusionjs/rfcs#8

cc @ganemone

@chrisgervang
Copy link
Author

When will the RFC be implemented?

@chrisgervang
Copy link
Author

chrisgervang commented Dec 11, 2018

We've disabled server side redux store and rendering to work around the issue. As our applications grow, we've put class types, like Date object and Protobuf objects in our stores. We'll consider enabling it again when we have the ability to extend the serialize/deserialize functions.

For reference, this is our plugin change:

import {RenderToken} from 'fusion-core';
import {compose} from 'redux';
import ReactReduxPlugin, {
  ReduxToken,
  ReducerToken,
  EnhancerToken,
} from 'fusion-plugin-react-redux';

// ensure nothing is rendered/mounted in server
if (__NODE__) {
    app.register(RenderToken, () => {
      return '<div id="root"></div>';
    });
}

// ensure redux store is only built in browser
if (__BROWSER__) {
    app.register(ReduxToken, ReactReduxPlugin);
    app.register(ReducerToken, reduxReducer);
    app.register(EnhancerToken, ActionEmitterEnhancerPlugin);
    if (reduxEnhancer) {
        app.enhance(EnhancerToken, prevEnhancer => {
            return compose(prevEnhancer, reduxEnhancer);
        });
    }
}

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants