With a few lines of code, you can setup a new create-react-app project with hot-module-replacement (HMR).
Spin up a new react app withnpx create-react-app your-new-app
and update the index.js
file and voila (see the gist below).
But what if I start adding other react things?
- react-router-dom
- redux
- react-redux
Suddenly, HMR doesnāt work when I wrap my App
with Provider
and BrowserRouter
.
I googled around for clues and found my aha moment in the create-react-app github issues:
I tweaked my code accordingly and now my app works with HMR functioning correctly. See with the gists below.
Thatās it.
You can stop reading now.
The rest of this article is a bunch of crazy notes because I feel terrible about not knowing how any of this stuff works. The āwebpack-layerā is magic to me and Iād like to understand it better. Itās the off-chance that youāll continue reading that motivates me to write anything at all. SO even though these are notes for myselfā¦thanks for reading and hope you get something out of this.
Thereās a āwebpack-shapedā hole in my brain
Oh, youāre still here? Alright..wellā¦
Iām going to allow my webpack-noobness to show a little: I donāt know webpack well enough to work with it directly. I do my best to avoid ejecting my projects that use create-react-app. Apologies if this offends anyone but š¤·āāļø
Even though I have HMR playing nicely with everything else, now I get to use the code I have to understand whatās going on under-the-hood.
Attempting to understand
This module.hot
code seems to be the thing ā I think itās a webpack thing.
Iām going to go read these docs and these docs. Iāll update this later with some better written thoughts. Hereās a donut š©, enjoy!
API
The API for module.hot
looks like itās short and sweet.
if (module.hot) {
module.hot.accept('./library.js', function() {
// Do something with the updated library module...
})
}
- Check if there are any spicy modules
- accept them spicy mods
- do something in the callback with that module
This makes sense so farā¦App
should be accepted, and we get the updated App
component and render it with ReactDOM.render
in the callback
.
if (module.hot) {
module.hot.accept('./App', () => {
const NextApp = require('./App').default;
// render with new App here
});
}
But a few things are still weird to me:
- Why is it okay to give
module.hot.accept
a string like,'./App'
?
My guess here is that something is happening under the hood thatās resolving the string'./App'
to the actual App component. Or itās some reference? - What the heck is
require('./App').default
?
This exchange on stackoverflow is the closest thing I can find to an answer, so Iāll need to dig into this a little more.
Other cool stuff
Ejecting create-react-app reveals the webpack config files.
One thing to note is that thereās a custom dev client being used:
{
entry: [
require.resolve('react-dev-utils/webpackHotDevClient'),
],
}
Thereās also a comment that explains that this basically replaces this code but with added features for better dev experience, like error display:
require.resolve(āwebpack-dev-server/clientā) + ā?/ā, require.resolve(āwebpack/hot/dev-serverā),
Links
- Hot Reloading + create-react-app by Charlie Gleason
- Hot Modules Replacement docs from Webpack
- My Aha moment from Dan Abramov via GitHub
- My other Aha moment from Ro Savage via GitHub