9

When I render a synchronous route on server-side and then the client side hydrate the dom, I get a warning because client side asynchronous route doesn't find the component.

image

In other hand react fiber reconciliation tries to remove this non hydratable node. So the page makes a blank flash on client side :(

image

According to this next screenshot, the generated node from server side rendering will be remove. This node (div.home-page) is a dynamic component of the current route

image

So, how can I tell the reconciler to not remove this node, because it will be hydrated by the dynamic imported corresponding component?

Some code snippets for more explanations

Routes definition

import {
  HomePage,
} from '../bundles/Bundles';

export default [
  {
    component: HomePage,
    path: '/',
    exact: true,
    strict: true,
  },
];

The Bundles.js used on server side

export const HomePage = syncComponent('HomePage', require('../views/HomePage/HomePage'));

The AsyncBundles.js used on client side

export const HomePage = asyncComponent('HomePage', () => Promise.all([
  import('../views/HomePage/HomePage' /* webpackChunkName: 'HomePage' */),
  importCss('HomePage'),
]));

Thanks to the NormalModuleReplacementPlugin webpack plugin I'm able to switch from Bundles.js and AsyncBundles.js for server and client rendering

new webpack.NormalModuleReplacementPlugin(/Bundles\.js/, 'AsyncBundles.js')

HomePage.js component renders a simple div

<div className="home-page">Home Page</div>

The main Wrapper.js that renders the routes

  <Route
    render={({ location }) => (
      <div className="app__wrapper">
        <Switch location={location}>
          {routes.map((route, index) => (
            <Route
              key={route.path}
              path={route.path}
              exact={route.exact}
              render={route.component}
            />
          ))}
          <Route
            key={'not found'}
            path={'*'}
            render={NotFound}
          />
        </Switch>
      </div>
    )}
  />

The html generated on server-side looks like this:

<div class="app__wrapper">
  <div class="home-page">
    Home Page
  </div>
</div>

When I open the chrome debugger timeline, I get a flashing blank frame image

Before the blank frame, it's the rendered html, after it's the chunked HomePage.123456.js that is rendered

Michael Rasoahaingo
  • 1,069
  • 6
  • 11
  • 1
    Hey did you get a solution to this. I am facing the same situation. If you've found a solution could you please share it. – Nitish Phanse Dec 12 '17 at 23:43
  • This is happening because the react render pass is synchronous, on first pass the `import` function is not loaded yet: it will always take at least another tick (and therefore a second render pass) to load. To resolve this you need to load the async chunks before the first render pass and have the async component replace the "import" function with something synchronous. This is non-trivial and AFAIK there is no simple library around that will do this. – bm_i Jan 15 '18 at 10:07
  • Yes, that's why i used an HOC like react-loadable or react-async-component which resolve all import before rendering to the dom – Michael Rasoahaingo Jan 16 '18 at 10:36
  • This is currently the best solution available: https://github.com/faceyspacey/react-universal-component – bm_i Jan 16 '18 at 15:14

0 Answers0