Currently I\'m struggling to get HMR working in my Webpack 2 setup. I\'ll explain my entire setup so I hope this is enough for someone to understand what\'s happening.
The imports are static and after an update has been identified in module.hot.accept
you render the exact same component again, as the TodoApp
still holds the old version of your module and HMR realises that and doesn't refresh or change anything in your app.
You want to use Dynamic import: import(). To make it work with babel you need to add babel-plugin-syntax-dynamic-import
, otherwise it will report a syntax error as it didn't expect import
to be used as a function. The react-hot-loader/babel
is not needed if you use react-hot-loader/patch
in your webpack config, so your plugins in your .babelrc
become:
"plugins": [
"syntax-dynamic-import"
]
In your render()
function you can now import the TodoApp
and render it.
const render = () => {
import('./components/TodoApp').then(({ default: Component }) => {
ReactDOM.render(
<AppContainer>
<Component />
</AppContainer>,
document.querySelector('#main')
);
});
};
render();
// Hot Module Replacement API
if (module.hot) {
module.hot.accept('./components/TodoApp', render);
}
import()
is a promise that will resolve with the module, and you want to use the default
export.
Even though the above is true, the webpack documentation doesn't require you to use dynamic imports, because webpack handles ES modules out of the box, also described in react-hot-loader docs - Webpack 2, and because webpack is also handling the HMR, it will know what to do in that case. For this to work, you must not transform the modules to commonjs. You did this with ["es2015", {"modules": false}]
, but you also have the latest
preset configured in your webpack config, which also transforms the modules. To avoid confusion, you should have all babel configurations in .babelrc
instead of splitting some to the loader options.
Remove the presets in the babel-loader
entirely from your webpack config and it will work as you already have the necessary presets in your .babelrc
. babel-preset-latest is deprecated and if you want to use these features you should start using babel-preset-env which also replaces es2015
. So your presets in .babelrc
would be:
"presets": [
["env", {"modules": false}],
"react"
],
Check this issue on GitHub or just use this in your index.js:
import React from 'react'
import ReactDOM from 'react-dom'
import { AppContainer } from 'react-hot-loader'
import App from './components/App'
const render = Component => {
ReactDOM.render(
<AppContainer>
<Component/>
</AppContainer>,
document.getElementById('react-root')
)
}
render(App)
if(module.hot) {
module.hot.accept();
}