Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code splitting problem in 1.0.0-beta2 #1402

Closed
heebtob opened this issue Jun 24, 2015 · 7 comments
Closed

Code splitting problem in 1.0.0-beta2 #1402

heebtob opened this issue Jun 24, 2015 · 7 comments

Comments

@heebtob
Copy link
Contributor

heebtob commented Jun 24, 2015

I use server side rendering with fluxible and react router.

I have some routes with code splitting like the following

exports.SearchResultPage = {
    path: '/search/:searchQuery',

    getComponents(cb) {
        require.ensure([], (require) => {
            cb(null, {
                navigationBar: require('./components/ReaderNavigationBar/ReaderNavigationBar'),
                content: require('./pages/SearchResultPage')
            });
        });
    }
};

As soon as I go to a route with code splitting in place I get the following warning in the browser

Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server:
 (client) <noscript data-reacti
 (server) <div class="c-app" da

React checks the server side generated markup against the following markup and says it can not be reused because it's differrent.

<noscript data-reactid=".18nkp8inv9c"></noscript>
@anatomic
Copy link

I am currently fighting this battle and I think it's related to the async patterns for loading components and routes.

What I think happens is that one of the async loops completes, presenting the routes to the Router but with null in place of components (as they are yet to fully load async). React then attempts to render, triggering it's EmptyComponent injection - a noscript element.

I've not worked out how to mitigate this problem yet, I would assume it will require some addtional async control flow to ensure that both getComponents and getChildRoutes are fully resolved before rendering

@anatomic
Copy link

Just to add to this, the following is the console output when I was debugging the issue. It's exactly as I described above, the Router is mounted and starts the async process of resolving routes and getting the components for the route branch, however, this does not complete before an initial render of the router (which does not have components). I think this is where the noscript is output.

Then the async process of getting components returns, calling the callback passed to runTransition which ultimately causes another two render passes. The first of which should match the initial checksum from the server side render.

I guess the issue here is how to cancel the first render of the Router until the components are returned from getComponents

Router.js:264 - component will mount in router, update state using location
Router.js:151 - _updateState called
Router.js:69 - runTransition: transitionHooks completed
Router.js:73 - runTransition: getComponents
Router.js:266 - continuing to mount router
Router.js:313 - render router
Router.js:314 - router: transitioning - true
Router.js:343 - render does not have components
warning.js:48 - Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server:
 (client) <noscript data-reacti
 (server) <div data-reactid=".1
Router.js:78 - runtransition: getComponents returned
Router.js:80 - runtransition: call callback with nextState and transition
Router.js:164 - runTransition callback
Router.js:187 - runTransition callback: setState
Router.js:313 - render router
Router.js:314 - router: transitioning - true
Router.js:317 - render has components
Router.js:191 - runTransition callback: isTransitioning: false
Router.js:313 - render router
Router.js:314 - router: transitioning - false
Router.js:317 - render has components

@anatomic
Copy link

After some further conversations on this in the React thread I've managed to workaround this issue. The key is to setup the routes ahead of the first render so I've essentially run the server-side rendering code again but then rendered the client-side version:

const history = new BrowserHistory();

if (typeof history.setup === "function") {
    history.setup();
}

Router.run(routes, history.location, (err, initialState, transition) => {
    React.render(<Provider redux={redux}>{() => <Router key="ta-app" history={history} children={routes} />}</Provider>, document.getElementById('ta-app'));
});

This appears to be working for me.

@heebtob
Copy link
Contributor Author

heebtob commented Jun 30, 2015

👍
You're the best.
I've tested it and it works.
Thanks very much for the Investigation!

@BerkeleyTrue
Copy link

Doing this causes the runTransition to happen twice. @anatomic or @heebtob Can you try out my PR here #1490 to see if you still get the odd behavior?

What this pr does is detect if the location object is actually a history object. Then extracts the location object, passing down the history object and routes object down with the initial state so Router run works client side.

Your code would then be reduced to:

const history = new BrowserHistory();

Router.run(routes, history, (err, initialState, transition) => {
    React.render(<Provider redux={redux}>{() => <Router key="ta-app" ...initialState />}</Provider>, document.getElementById('ta-app'));
});

@ryanflorence
Copy link
Member

this sounds like basic functionality that isn't working, so I'm closing since we're reworking the server rendering story a little bit right now, and we'll have tests around pretty basic functionality.

@BerkeleyTrue
Copy link

@ryanflorence Can you point me to the new server rendering stuff?

@lock lock bot locked as resolved and limited conversation to collaborators Jan 22, 2019
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

4 participants