Search code examples
javascriptreactjsreact-router-domserver-side-renderingloadable-component

Did not expect server HTML to contain a <div> in <main>


I'm working in a project that uses:

The application renders both server side and client side.

I'm using @loadable/component to dynamically code split this way.

router.tsx

import * as React from 'react'
import loadable from '@loadable/component'
import { Route, Switch } from 'react-router-dom'

const NotFound = loadable(() =>
  import('../components/NotFound/NotFound' /* webpackChunkName: "notfound" */)
)

const routes = (
  <Switch>
    <Route component={NotFound} />
  </Switch>
)

export default routes

When loading the page, this error appear on the console and the page seems to flick for a second.

react-dom.development.js:546 Warning: Did not expect server HTML to contain a <div> in <main>.

When I check the output in both sides (server/client), they are identical.

When I remove @loadable/component like bellow, it works and the error is gone.

router-without-loadable.tsx

import * as React from 'react'
import { Route, Switch } from 'react-router-dom'
import NotFound from '../components/NotFound/NotFound'

const routes = (
  <Switch>
    <Route component={NotFound} />
  </Switch>
)

export default routes

Seems to be something to do with @loadable/component but I'm not 100% sure.


Solution

  • Finally have an answer for this:

    1. For @loadable/component to work properly, you need to put the magic webpack comment (/* webpackChunkName: "notfound" */) before the path of the file this way.
    const NotFound = loadable(() =>
      import(/* webpackChunkName: "notfound" */ '../components/NotFound/NotFound')
    )
    

    Reference:

    https://github.com/smooth-code/loadable-components/issues/23

    1. And more important, in the server side, you need to wrap you app in a ChunkExtractorManager and pass the client extractor (I was passing the server extractor, it's not very clear in the docs).
    const statsFile = path.resolve('./wwwroot/dist/loadable-stats.json')
    const extractor = new ChunkExtractor({ 
      statsFile, 
      entrypoints: ['client'] // name of the proper webpack endpoint (default: main)
    })
    
    <ChunkExtractorManager extractor={extractor}>
      <App />
    </ChunkExtractorManager>
    

    Here is a proper clear example on how to implement it:

    https://github.com/iamssen/seed

    Update 24.09.2019

    Added to the official docs

    https://www.smooth-code.com/open-source/loadable-components/docs/server-side-rendering/#chunkextractor-entrypoints