Mastering Webpack Hot Module Replacement: Boost Your Development Speed
This article explains what Webpack's Hot Module Replacement (HMR) is, walks through its configuration steps, and dives deep into the underlying mechanisms—including the dev server, socket communication, and HotModuleReplacementPlugin—showing how HMR enables instant, state‑preserving updates during development.
What is Module Hot Replacement (HMR) and How It Works?
Hot Module Replacement (HMR) is one of Webpack's most useful features; it allows updating all types of modules at runtime without a full page refresh.
Running a simple example demonstrates HMR: changing a CSS color updates the page instantly while preserving the content of input fields, saving developers from manual refreshes and preserving state.
How does HMR trigger automatic recompilation?
How does the browser detect changes in module content?
What are the two extra files generated by HMR?
How does partial updating work?
Below we explore the principles behind HMR.
Configuration for HMR
Before diving into the internals, set up HMR correctly.
Step 1: Install webpack-dev-server npm install --save-dev webpack-dev-server Step 2: Register module.hot.accept in the entry module
// src/index.js
let div = document.createElement('div');
document.body.appendChild(div);
let input = document.createElement('input');
document.body.appendChild(input);
let render = () => {
let title = require('./title.js');
div.innerHTML = title;
};
render();
// Add HMR handling
if (module.hot) {
module.hot.accept(['./title.js'], render);
}Step 3: Enable hot mode in webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'development',
devtool: 'source-map',
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
devServer: {
hot: true
},
plugins: [new HtmlWebpackPlugin()]
};Even without explicitly calling module.hot.accept, most loaders handle HMR automatically because they inject the necessary code behind the scenes.
Webpack‑dev‑server provides live reloading, but true partial updates require the additional configuration above and the HotModuleReplacementPlugin.
HMR Principle
1. Webpack‑dev‑server
The dev server reads its entry point from node_modules/webpack-dev-server/package.json and runs node_modules/webpack-dev-server/bin/webpack-dev-server.js.
The server creates a compiler instance, starts an HTTP server, and upgrades it to a WebSocket server. When a browser connects, the server sends a hash value and an "ok" signal to establish two‑way communication.
// node_modules/webpack-dev-server/bin/webpack-dev-server.js
const webpack = require('webpack');
const config = require('../../webpack.config');
const Server = require('../lib/Server');
const compiler = webpack(config);
const server = new Server(compiler);
server.listen(8080, 'localhost', () => {});The server also listens for the compiler's done hook to broadcast the new hash to all connected browsers.
// Inside Server.js
setupHooks() {
const { compiler } = this;
compiler.hooks.done.tap('webpack-dev-server', (stats) => {
this.currentHash = stats.hash;
this.clientSocketList.forEach(socket => {
socket.emit('hash', this.currentHash);
socket.emit('ok');
});
});
}2. File Watching
Webpack‑dev‑middleware watches source files via compiler.watch and writes compiled assets to an in‑memory file system ( memory-fs), enabling fast reads without touching the disk.
// node_modules/webpack-dev-middleware/index.js
const MemoryFs = require('memory-fs');
compiler.watch({}, () => {});
let fs = new MemoryFs();
this.fs = compiler.outputFileSystem = fs;3. Injecting Client Code
Before starting the HTTP server, the dev server modifies the compiler's entry to include two client scripts: one for establishing the WebSocket connection and another for handling hot updates.
// node_modules/webpack-dev-server/lib/utils/updateCompiler.js
compiler.options.entry = {
main: [
path.resolve(__dirname, '../../client/index.js'),
path.resolve(__dirname, '../../../webpack/hot/dev-server.js'),
config.entry,
]
};The client code ( client/index.js) creates a socket, stores the latest hash, and reloads the app when an "ok" message arrives.
let currentHash;
let hotEmitter = new EventEmitter();
const socket = window.io('/');
socket.on('hash', hash => { currentHash = hash; });
socket.on('ok', () => { reloadApp(); });
function reloadApp() { hotEmitter.emit('webpackHotUpdate', currentHash); }4. HotModuleReplacementPlugin
The plugin adds a hot property to each module, defines accept and check methods, and generates two patch files after recompilation: a .hot-update.json describing which chunks changed, and a .hot-update.js containing the updated module code.
function hotCreateModule() {
let hot = {
_acceptedDependencies: {},
accept(deps, callback) { deps.forEach(dep => hot._acceptedDependencies[dep] = callback); },
check: hotCheck
};
return hot;
}When the browser receives the JSON manifest, it requests the corresponding .hot-update.js via a dynamically created <script> tag, which then calls window.webpackHotUpdate to apply the new modules.
function hotDownloadManifest() {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
let url = `${lastHash}.hot-update.json`;
xhr.open('get', url);
xhr.responseType = 'json';
xhr.onload = () => resolve(xhr.response);
xhr.send();
});
}
function hotDownloadUpdateChunk(chunkId) {
let script = document.createElement('script');
script.src = `${chunkId}.${lastHash}.hot-update.js`;
document.head.appendChild(script);
}
window.webpackHotUpdate = function(chunkId, moreModules) {
hotAddUpdateChunk(chunkId, moreModules);
};The update process replaces the old module in the module cache, runs the registered accept callbacks, and thus updates only the affected parts of the page while keeping the rest of the state intact.
Summary
When npm run dev starts, updateCompiler injects client scripts into main.js. The dev server watches source changes, recompiles to memory, and notifies browsers via WebSocket. The HotModuleReplacementPlugin generates patch files that the browser fetches, applies, and triggers the developer‑defined callbacks, achieving instant, state‑preserving updates.
References
Webpack Documentation – Hot Module Replacement: https://webpack.docschina.org/guides/hot-module-replacement/
Understanding Webpack HMR – Juejin: https://juejin.cn/post/6844904008432222215
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
