Webpack 的热更新(HMR, Hot Module Replacement)原理核心在于:不刷新整个页面,只替换发生变化的模块,从而保持应用状态,提高开发效率。
HMR 工作流程
整个过程可以分为 5 个核心步骤:
1. 启动 Dev Server
-
使用 webpack-dev-server 或 webpack-hot-middleware 启动服务。
-
Dev Server 使用 Express 启动本地服务器,默认端口 8080。
-
内部集成 webpack-dev-middleware,用来把构建产物保存在 内存中(不是 dist 目录)。
2. 建立 WebSocket 连接
-
浏览器端运行一个 HMR Client(通常注入到入口文件)。
-
HMR Client 通过 WebSocket 与 Dev Server 建立长连接。
-
当源码变化时,Dev Server 会通过 WebSocket 向客户端 发送更新消息。
3. 文件变化 → 重新编译
-
当源码文件修改时,webpack 监听到变化,触发 重新编译。
-
Webpack 使用 增量编译(只编译改动的模块及依赖)。
-
生成 新的编译产物(chunk hash 变化)。
4. 生成更新补丁(Manifest + Chunk)
-
Webpack 会生成 manifest(清单文件),记录哪些模块变了。
-
同时生成 更新模块的 JS 文件(称为 hot-update.js)。
-
Dev Server 通过 WebSocket 告诉客户端:哪些模块更新了,以及更新文件的 URL。
5. 客户端替换模块
-
浏览器端的 HMR Runtime 收到更新通知后:
-
通过 JSONP 或 fetch 拉取 hot-update.js。
-
使用 webpack_require.hot.accept() 钩子,替换对应模块的逻辑。
-
不会刷新页面,只执行更新模块的代码。
-
-
如果更新失败(比如模块不支持 HMR),则会 回退到页面刷新。
关键技术点
-
WebSocket 通信:实现双向实时推送。
-
增量编译:只重新打包修改部分,减少构建时间。
-
模块热替换 API:module.hot.accept(),开发者可自定义更新逻辑。
-
回退机制:不支持 HMR 的情况,执行 window.location.reload()。
流程图(简化)
源码改动 → webpack 重新编译 → 生成 hot-update.js↓
Dev Server 通知客户端(WebSocket)↓
客户端拉取补丁 → 替换模块 → 视图更新(状态保留)
HMR 和 Live Reload 区别
特性 | HMR | Live Reload |
---|---|---|
页面是否刷新 | ❌ 否(只替换模块) | ✅ 是(整页刷新) |
状态是否保留 | ✅ 保留(React 组件状态) | ❌ 丢失 |
性能 | 高效(只更新部分代码) | 低效(刷新整个页面) |