webpack 中什么是 HMR,原理是什么
Issue 欢迎在 Gtihub Issue 中回答此问题: Issue 79
Author 回答者: wjw-gavin
HMR(Hot Module Replacement),热更新又称热替换,基于 webpack-dev-server。 第一步:webpack 对文件系统进行 watch 打包到内存中 第二步:devServer 通知浏览器端文件发生改变,在这一阶段,sockjs 是服务端和浏览器端之间的桥梁,在启动 devServer 的时候,sockjs 在服务端和浏览器端建立了一个 webSocket 长连接,以便将 webpack 编译和打包的各个阶段状态告知浏览器 第三步:webpack-dev-server/client 接收到服务端消息做出响应 第四步:webpack 接收到最新 hash 值验证并请求模块代码 第五步:HotModuleReplacement.runtime 对模块进行热更新 第六步:调用accept 方法,及时将新后的内容插入到页面中
Author 回答者: shfshanyue
@wjw-gavin 可以把其中的 npm 包列出来,比如 webpack 如何对 fs 进行watch的
Author 回答者: shfshanyue
HMR,Hot Module Replacement,热模块替换,见名思意,即无需刷新在内存环境中即可替换掉过旧模块。与 Live Reload 相对应。
PS: Live Reload,当代码进行更新后,在浏览器自动刷新以获取最新前端代码。
在 webpack 的运行时中 __webpack__modules__
用以维护所有的模块。
而热模块替换的原理,即通过 chunk
的方式加载最新的 modules
,找到 __webpack__modules__
中对应的模块逐一替换,并删除其上下缓存。
其精简数据结构用以下代码表示:
// webpack 运行时代码
const __webpack_modules = [
(module, exports, __webpack_require__) => {
__webpack_require__(0);
},
() => {
console.log("这是一号模块");
},
];
// HMR Chunk 代码
// JSONP 异步加载的所需要更新的 modules,并在 __webpack_modules__ 中进行替换
self["webpackHotUpdate"](0, {
1: () => {
console.log("这是最新的一号模块");
},
});
其下为更具体更完整的流程,每一步都涉及众多,有兴趣的可阅读 webpack-dev-server
及开发环境 webpack 运行时的源码。
webpack-dev-server
将打包输出 bundle 使用内存型文件系统控制,而非真实的文件系统。此时使用的是 memfs 模拟 node.jsfs
API- 每当文件发生变更时,
webpack
将会重新编译,webpack-dev-server
将会监控到此时文件变更事件,并找到其对应的module
。此时使用的是 chokidar 监控文件变更 webpack-dev-server
将会把变更模块通知到浏览器端,此时使用websocket
与浏览器进行交流。此时使用的是 ws- 浏览器根据
websocket
接收到 hash,并通过 hash 以 JSONP 的方式请求更新模块的 chunk - 浏览器加载 chunk,并使用新的模块对旧模块进行热替换,并删除其缓存