开着飞机修引擎---热更新

本文最后更新于:2021/07/05 , 星期一 , 21:32

在自己刚开始学习前端的时候,每次修改个新样式都要手动刷新一下页面。随着自己对前端的了解,开始使用了 live reload 插件进行代替,每次更改文件后,浏览器都会代替人工来刷新页面。随着后面的学习 React,发现使用 CRA 创建的东西可以在开着服务的时候进行不刷新就替换内容。

live reload

使用 webpack 的 dev-server 模拟当年的 nginx+live-reload 插件
webpack 配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
entry: "./src/index.js",
mode: "development",
plugins: [
new HtmlWebpackPlugin({
title: "Development",
}),
],
output: {
filename: "[name].bundle.js",
path: path.resolve(__dirname, "dist"),
clean: true,
},
devServer: {
contentBase: "./dist",
open: true,
},
};

打开页面后,打开控制台的 network 标签可以看到其中有一条是 websocket 的连接。

websocket

查看这条记录,发现内部写了要进行的操作,以及更新的文件 hash 值(可以与上图中文件的 hash 对比一下,是完全一致的)。

websocket内容

通过这个 websocket 链接,就可以使打开的网页和本地服务间建立持久化的通信。当源代码发生变更时,就通过 Socket 通知到浏览器,浏览器在接到通知后会自动触发页面刷新。

虽然这样也很方便,但是会有一个问题。页面的刷新会导致状态丢失:比如我在标中填充好的东西需要再重新填。

Hot Module Replacement

开启 webpack 的热更新模块功能,配置如下

1
2
3
4
5
6
7
8
9
module.exports = {
...
devServer: {
contentBase: "./dist",
hot: true
},
...
};

开启服务后,修改一个 CSS 文件看看。

可以看到,websocket 这条记录中先通知了浏览器有文件更新了,通过服务端可以看出来,更新的 hash 可以对上。

但是为什么更新了css文件,他这面却更新的是 JS 呢?因为在使用 webpack 的过程中,webpack 将 css 的内容合并到了 js 中。

修改style文件引起的network变化

websocket内容详细

webpack-server内容

随后他请求了原文件(入口文件?)的 hash.hot.update.json 获取要更新的模块,然后再根据 json 内返回的模块内容去请求更新后的模块。

这也可以解释为什么更新 CSS 是加载模块,但是更新 JS 文件却是 reload。因为原文件(入口文件?)的 hash 值变了。

hot-updatejs内容

至此大致流程已经明白了,画个简单的流程图看看吧

热更新流程图