React Loadable with server-render

How can I make React Loadable work with server-render for SSR?

On the React Loadable page, it looks pretty complex to set that up right with other server/build software. The important part seems to be that you have to “preload” all the modules on the server during startup - before the server starts listening for requests. How would I set something like that up with Meteor?

It works. You can find the repository here: https://github.com/minhna/meteor-react-ssr and the demo site http://meteor-ssr-loadable.minhnguyen.me/

I did get it to work just after posting this (at 3 in the morning heh).

All I had to do was call the preload method. This probably leaves an opening during startup (or just after startup - basically while it preloads all the Loadable components) that the server will not respond correctly, but it should mostly be fine.

Here’s my code:

Loadable.preloadAll().then(() => {
  console.log('preloaded')
})

onPageLoad(sink => {
  const context = {}
  const modules = []
  sink.renderIntoElementById('react-root', renderToString(
    <Loadable.Capture report={moduleName => modules.push(moduleName)}>
      <StaticRouter location={sink.request.url} context={context}>
        <App />
      </StaticRouter>
    </Loadable.Capture>
  ))
  console.log(modules)
})

There are some peculiarities though - I don’t get any modules in the console log (the array is empty), even though if I look at the source, it does output the html. Also, the preloadAll().then(...) method is never called (neither is .catch).

1 Like

One problem I’m continuing to have, is that I get this error:

Warning: Did not expect server HTML to contain a <div> in <div>.

Even though I’m sure the HTML is exactly the same whether rendered on the server or the client. Any ideas what might cause that?

Yes, there is that warning on dev site. But when you deploy the production site, there is no warning.
I have no idea how to fix that.

Hi! where is the babel config in your starter?

It’s in package.json - I prefer to put as much in there as possible. (er, that may not have been for me?)

I thought you were talking about my starter. I did get SSR working with react-loadable. I had to fork react-loadable to make it work though…

unfortunately I can’t make it work, but I did all setup steps:

  1. Package.json babel
  2. server PreloadAll
  3. client:
const fetchedData = window._initState_;
    onPageLoad(async sink => {
        if (fetchedData) {
            await Loadable.preloadablesReady(fetchedData)
        }
        hydrate(
            <MuiThemeProvider theme={theme}>
                <ClientApp/>
            </MuiThemeProvider>, document.getElementById('main-app')
        );
    })

but not use your LateLoadable

const LateLoadable = (config) => class extends Component {
  loadable = Loadable(config)
  render () {
    return <this.loadable {...this.props} />
  }
}

how important is it ?
why modulesResolved can be empty?

If modulesResolved is empty, you either didn’t load the babel plugin, or you have obfuscated the Loadable instance to prevent the babel plugin from working. LateLoadable is meant to avoid the babel plugin from working on those instances, so that they don’t get loaded on the server. But for anything you want loaded on the server, you have to use the Loadable interface directly.

Oh also make sure you are using my fork of react loadable, and that you are using the reportResolved property. Follow my starter for an example

Thanks for reply,
you did a great job doing this starter kit, which shows that Meteor-SSR with code splitting quite realistic and possible just now,
but with forked ReactLoadable approach it looks like a temporary solution, I would like to rely on the more stable or native solution mentioned in the Meteor Roadmap,
I hope soon will be a solution based on dynamic import

Which stable/mature apparch do you mean? I’m using the Meteor SSR platform.

React-Loadable’s maintainer doesn’t seem to accept PRs (I sent one), so I’m not sure the mainline react-loadable code would be any more reliable. It only supports webpack SSR as it is.

I’m hoping to find some time to do a proper port of this to a meteor specific package, but it’ll probably be a couple of months before I get to that.

I meant the third point of RoadMap :slight_smile:
maybe news coming soon?

I think React Suspense is gonna obsolete a lot of the tooling around this, anyways. There will be no need for react-loadable (and similar things) if the view library itself supports dynamic loading.

I did not know about it, great news!
but still need integrate this with server rendering?

I’m not aware of any attempt to enable react SSR other than through projects like React Loadable. Would love to hear more if there is more thought surrounding this idea than I’m aware of.

React Suspense looks great, but you are still going to want some kind of abstraction around that. That (like the new context API) will make certain types of things we currently do easier/nicer, but React Loadable is a nice neat little package with a declarative API. It’ll still have value even with Suspense.

And even with Suspense, you’ll still need an SSR solution.

1 Like