loadable-components breaks Hot Module Replacement (HMR)

Created on 18 Feb 2019  路  10Comments  路  Source: gregberge/loadable-components

馃悰 Bug Report

HMR updates are not applied if components are imported with @loadable/component. By not applied, I mean that in Chrome console panel:

image

and network panel

screen shot 2019-02-18 at 15 48 53

you can see the update is there, but it's not reflected in the DOM.

To Reproduce

In the linked repo, make sure the first line is commented, and change the text in ./LoadableComponents

// import LoadableComponents from './LoadableComponents'
import loadable from '@loadable/component'
const LoadableComponents = loadable(() => import('./LoadableComponents'))

If you change the code like this:

import LoadableComponents from './LoadableComponents'
// import loadable from '@loadable/component'
// const LoadableComponents = loadable(() => import('./LoadableComponents'))

Everything works as expected.

Expected behavior

Code splitting should work with loadable-components.

Link repo

Run npx envinfo --system --binaries --npmPackages @loadable/component,@loadable/server,@loadable/webpack-plugin,@loadable/babel-plugin --markdown --clipboard

Paste the results here:

## System:
 - OS: macOS High Sierra 10.13.6
 - CPU: (4) x64 Intel(R) Core(TM) i7-5557U CPU @ 3.10GHz
 - Memory: 2.71 GB / 16.00 GB
 - Shell: 5.3 - /bin/zsh
## Binaries:
 - Node: 10.15.0 - ~/.nvm/versions/node/v10.15.0/bin/node
 - Yarn: 1.13.0 - /usr/local/bin/yarn
 - npm: 6.4.1 - ~/.nvm/versions/node/v10.15.0/bin/npm
 - Watchman: 4.9.0 - /usr/local/bin/watchman
## npmPackages:
 - @loadable/component: ^5.6.0 => 5.6.0

_Nota bene_

I'm happy to help.

Most helpful comment

Thank you both for your help. I didn't know adding multiple hot was an option, fixed my problem. I will update the link repo with the recommended solution.

All 10 comments

Hello @mathieux51. I think it is an issue for @theKashey. Anyway I will not change the code of Loadable Components to be compatible with React Hot Loader.

Ok. Thanks for you answer. I will create a similar issue on react-hot-loader repo and reference this one.

There is 3 options to fix it:

  1. use React.lazy. React-Hot-Loader "knew it" and could call the import function. It's possible to use React.lazy inside loadable component, instead of _throwing promises_, but async mode is not default.
  2. on componentDidUpdate compare ctor and ctor you will store somewhere(in state or class variable). If they are different - you got updated.
  3. call ctor in a constructor, not in componentDidMount. That's the most common way.

RHL could not help you, as long as ctor(import function) is not visible from a component - it's a variable on a scope.

For now - the only way is to apply hot to an export of an imported component. So - make it reloadable by itself - check RHL documentation.

Thank you both for your help. I didn't know adding multiple hot was an option, fixed my problem. I will update the link repo with the recommended solution.

FYI, I ended up having an other issue with HOCs that I solved by removing the "new" hot and replacing it with:

if (module.hot) {
  module.hot.accept('./Root', () => {
    const NextRoot = require('./Root').default
    render(NextRoot)
  })
}

I know it's not the recommended way but it works now so I'm happy.

So you are just remounting application from a scratch - you have the code update, but the hot-update problems.
馃憤 working as it should
馃憥 state loss

PS: you don't have to const NextRoot = require('./Root').default with esm modules, webpack will handle it.

Has anybody tried "Fast refresh" using this plugin: https://github.com/pmmmwh/react-refresh-webpack-plugin

I'm guessing that there will be a similar issue.

I created a linked issue: https://github.com/pmmmwh/react-refresh-webpack-plugin/issues/48

Loadable is yet class based and it's internal state would be lost on HMR, casing old tree to be remounted, new component be loaded, and rendered again. So again - all state would be lost.

You may want to consider turning off code splitting in a local environment.
new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 }),

Was this page helpful?
0 / 5 - 0 ratings