Webpack has a nifty feature called Hot Module Replacement [HMR] that helps replace old modules with the newer ones without reloading the browser. This is very helpful in many cases, for example when working with some dialog box or 3rd page of a navigation wizard and so on. In these cases you want to see the changes but reloading the browser to see the changes takes the app back to initial screen.
You may be using it already but may not know exactly how it works. So in this blog, I’ll go over how it works.
Things To Note About HMR
- HMR is one of Webpack’s optional features and needs to be turned ON explicitly.
- You need to use Webpack via webpack-dev-server, one of Webpack’s two interfaces (the other one is the CLI).
- It can only work with “loaders” that implement and understand HMR API. For example: “style-loader”, “react-hot-loader” etc.
- It should only be used for development because it adds a lot of extra code and secondly, webpack-dev-server is development-only server.
How It Works
Webpack injects a whole lot of JS libraries to make HMR work. The below picture shows how various parts work when a file/module change to make it happen.
Note: You can click on the picture to zoom and read
Legend:
Green — Webpack-dev-server related libs.
Blue — Webpack core and plugin libs.
Orange — chunk manifest or chunk JS file itself.
Red — React-loader or Style-loader HMR libs.
Teal — Your App
Purple — File or module that just changed.A JS or CSS file (module) changes
- Webpack uses HotModuleReplacementPlugin to generate a manifest(a JSON containing list of changed modules) and an update file(a JS with the actual change info).
- Webpack then tells webpack-dev-server about the changes
- webpack-dev-server tells “webpack-dev-server/client”(JS file) running in the browser via webSocket by sending “invalid” notification via WebSocket.
- “webpack-dev-server/client” then sends the initial hash(e.g. b2e2d54372f42c1b2352) that it got when the app was first loaded to hot/dev-server library. “hot/dev-server” acts like the main interface to all other JS files.
- “hot/dev-server” then calls internal libraries(like JSONP runtime) that are also injected by Webpack to download the manifest file.
- JSONP runtime uses hash and loads the manifest file from the webpack-dev-server.
- The manifest file contains details about chunks that need to be uploaded to the browser. It’s file name looks like: b2e2d54372f42c1b2352.hot-update.json and it’s content looks like this: {“h”:”b3632c2a800d437e17df”,”c”:[0]}
- JSONP runtime then uses information contained inside the manifest file to load all the “Update” files and adds them to the DOM.
- “Updates JS” themselves are JS files. They contain information about actual changes that needs to be applied. They are added to the DOM and executed.
//Example: 0.b2e2d54372f42c1b2352.hot-update.js chunk
//Notice that the chunk is actually a function call to "webpackHotUpdate" HMR function. So when the chunk is loaded to the DOM, this function instantly called with the Chunk's info. //In this case, style-loader is telling HMR about a new CSS class:
//input { background: pink;} for module id "82"
webpackHotUpdate(0,
{
82:
function(module, exports, __webpack_require__) {
exports = module.exports = __webpack_require__(79)();
exports.push([module.id, “input {\n background: pink;\n}”, “”])
}
})
11. Updates call HMR runtime with the module id (e.g. moduleId “82” in the above example) and the actual changes.
12. But HMR runtime itself doesn’t know how to deal with the changes. So it delegates this job to corresponding loaders like react-hot-loader runtimes or style-loader runtimes to apply changes. (Note these are also injected into the Browser).
13. If there is no issues with applying the changes, the appropriate runtimes updates the module.
14. If there are issues (like syntax errors in the change), “hot/dev-server” lib is notified about the error. Note: if you are using “hot/dev-only-server”, an alternative to “hot/dev-server” then browser won’t reload.
A Deeper Look
Let’s take an example to see some of the above steps in details. Below is simple app that has a field and loads CSS (via css-loader and style-loader). The CSS currently changes body’s background color to gray.
With HMR working, if we change the background to green in the style.css file, HMR updates the app’s background to green without removing the text inside the input field (i.e. doesn’t reloads the browser and keeps the “state” as is).
0. Initial setup
Initially when you setup webpack-dev-server using — inline and — hot.
Note: You can click on the pictures to zoom and read
1. File Changed
Webpack along with HMR plugin generates a manifest file “<previousHash>.hot-update.json” and the update file “<cunkNumber>.<previousHash>.hot-update.js”.
Note the previousHash is the hash that’s generated when the app was first loaded and every time it’s patched. When ever there is a change to the modules, the “previousHash” is used to load new files and then a new hash is generated and set as “previousHash” and the cycle continues.
2. Update Client about the changes on the server
webpack-dev-server constantly communicates with the client about the changes via webSocket.
3. Upload changes
When webpack-dev-server receives “Invalid” notification via webSocket, it asks HMR libraries running in the client (browser) to load new files. The libraries use the current hash (e3472f4aac7404e2e5b2) and use it as part of the file name for manifest (e3472f4aac7404e2e5b2.hot-update.json) file and also for the changed file (0.e3472f4aac7404e2e5b2.hot-update.js). Note that the “0” is the chunk number.
Below picture shows the contents of the manifest file
4. Apply Changes
Below picture shows contents of the update file. Notice that it’s calling “webpackHotUpdate” function. So when this JS file is added to the DOM, it passes the details like module id, “78” and raw changes like (“background: green”) to the HMR runtime. HMR Runtime then passes this info the correct loader (i.e. style-loader HMR runtime) that knows how to deal with this change.
That’s it! 🙏
My Other Posts
Functional Programming
ES6
WebPack
- Webpack — The Confusing Parts
- Webpack & Hot Module Replacement [HMR]
- Webpack’s HMR And React-Hot-Loader — The Missing Manual
Draft.js
React And Redux :
- Step by Step Guide To Building React Redux Apps
- A Guide For Building A React Redux CRUD App (3-page app)
- Using Middlewares In React Redux Apps
- Adding A Robust Form Validation To React Redux Apps
- Securing React Redux Apps With JWT Tokens
- Handling Transactional Emails In React Redux Apps
- The Anatomy Of A React Redux App
Salesforce
🎉🎉🎉 If you like this post, please 1. ❤❤❤ it below on Medium and 2. please share it on Twitter. You may retweet the below card🎉🎉🎉
Thanks for reading! 👍