Skip to content

HMR 原理

1608382424775.png

服务器部分

步骤代码位置
1.启动 webpack-dev-server 服务器https://github.com/webpack/webpack-dev-server/blob/v3.7.2/bin/webpack-dev-server.js#L83
2.创建 webpack 实例https://github.com/webpack/webpack-dev-server/blob/v3.7.2/bin/webpack-dev-server.js#L89
3.创建 Server 服务器https://github.com/webpack/webpack-dev-server/blob/v3.7.2/bin/webpack-dev-server.js#L107
4.更改 config 的 entry 属性https://github.com/webpack/webpack-dev-server/blob/v3.7.2/lib/Server.js#L57
entry 添加 dev-server/client/index.jshttps://github.com/webpack/webpack-dev-server/blob/v3.7.2/lib/utils/addEntries.js#L22
entry 添加 webpack/hot/dev-server.jshttps://github.com/webpack/webpack-dev-server/blob/v3.7.2/lib/utils/addEntries.js#L30
5. setupHookshttps://github.com/webpack/webpack-dev-server/blob/v3.7.2/lib/Server.js#L122
6. 添加 webpack 的 done 事件回调https://github.com/webpack/webpack-dev-server/blob/v3.7.2/lib/Server.js#L183
编译完成向 websocket 客户端推送消息,最主要信息还是新模块的 hash 值,后面的步骤根据这一 hash 值来进行模块热替换https://github.com/webpack/webpack-dev-server/blob/v3.7.2/lib/Server.js#L178
7.创建 express 应用 apphttps://github.com/webpack/webpack-dev-server/blob/v3.7.2/lib/Server.js#L169
8. 添加 webpack-dev-middleware 中间件https://github.com/webpack/webpack-dev-server/blob/v3.7.2/lib/Server.js#L208
以 watch 模式启动 webpack 编译,文件系统中某一个文件发生修改,webpack 监听到文件变化,根据配置文件对模块重新编译打包https://github.com/webpack/webpack-dev-middleware/blob/v3.7.2/index.js#L41
设置文件系统为内存文件系统https://github.com/webpack/webpack-dev-middleware/blob/v3.7.2/index.js#L65
返回一个中间件,负责返回生成的文件https://github.com/webpack/webpack-dev-middleware/blob/v3.7.2/lib/middleware.js#L20
app 中使用 webpack-dev-middlerware 返回的中间件https://github.com/webpack/webpack-dev-server/blob/v3.7.2/lib/Server.js#L128
9. 创建 http 服务器并启动服务https://github.com/webpack/webpack-dev-server/blob/v3.7.2/lib/Server.js#L135
10. 使用 sockjs 在浏览器端和服务端之间建立一个 websocket 长连接https://github.com/webpack/webpack-dev-server/blob/v3.7.2/lib/Server.js#L745
创建 socket 服务器并监听 connection 事件https://github.com/webpack/webpack-dev-server/blob/v3.7.2/lib/servers/SockJSServer.js#L33

客户端部分

步骤代码位置
1.连接 websocket 服务器https://github.com/webpack/webpack-dev-server/blob/v3.7.2/client-src/default/socket.js#L25
2.websocket 客户端监听事件https://github.com/webpack/webpack-dev-server/blob/v3.7.2/client-src/default/socket.js#L53
监听 hash 事件,保存此 hash 值https://github.com/webpack/webpack-dev-server/blob/v3.7.2/client-src/default/index.js#L55
3.监听 ok 事件,执行 reloadApp 方法进行更新https://github.com/webpack/webpack-dev-server/blob/v3.7.2/client-src/default/index.js#L93
4. 在 reloadApp 中会进行判断,是否支持热更新,如果支持的话发射 webpackHotUpdate 事件,如果不支持则直接刷新浏览器https://github.com/webpack/webpack-dev-server/blob/v3.7.2/client-src/default/utils/reloadApp.js#L7
5. 在 webpack/hot/dev-server.js 会监听 webpackHotUpdate 事件https://github.com/webpack/webpack/blob/v4.39.1/hot/dev-server.js#L55
6. 在 check 方法里会调用 module.hot.check 方法https://github.com/webpack/webpack/blob/v4.39.1/hot/dev-server.js#L13
7. 调用 hotDownloadManifest,向 server 端发送 Ajax 请求,服务端返回一个 Manifest 文件(lastHash.hot-update.json),该 Manifest 包含了本次编译 hash 值 和 更新模块的 chunk 名https://github.com/webpack/webpack/blob/v4.39.1/lib/HotModuleReplacement.runtime.js#L180
8. 调用 JsonpMainTemplate.runtime 的 hotDownloadUpdateChunk 方法通过 JSONP 请求获取到最新的模块代码https://github.com/webpack/webpack/blob/v4.39.1/lib/web/JsonpMainTemplate.runtime.js#L14
9. 补丁 JS 取回来后会调用 JsonpMainTemplate.runtime.js 的 webpackHotUpdate 方法https://github.com/webpack/webpack/blob/v4.39.1/lib/web/JsonpMainTemplate.runtime.js#L8
10. 然后会调用 HotModuleReplacement.runtime.js 的 hotAddUpdateChunk 方法动态更新模块代码https://github.com/webpack/webpack/blob/v4.39.1/lib/HotModuleReplacement.runtime.js#L222
11.然后调用 hotApply 方法进行热更新https://github.com/webpack/webpack/blob/v4.39.1/lib/HotModuleReplacement.runtime.js#L257 https://github.com/webpack/webpack/blob/v4.39.1/lib/HotModuleReplacement.runtime.js#L278
12.从缓存中删除旧模块https://github.com/webpack/webpack/blob/v4.39.1/lib/HotModuleReplacement.runtime.js#L510
13.执行 accept 的回调https://github.com/webpack/webpack/blob/v4.39.1/lib/HotModuleReplacement.runtime.js#L569