webapck热更新基本原理

449 阅读4分钟

写在前面

来源:juejin.cn/post/684490…

Hot Module Replacement,简称HMR,无需完全刷新整个页面的同时,更新模块。HMR的好处,在日常开发工作中体会颇深:节省宝贵的开发时间、提升开发体验。

刷新我们一般分为两种:

  • 一种是页面刷新,不保留页面状态,就是简单粗暴,直接window.location.reload()
  • 另一种是基于WDS (Webpack-dev-server)的模块热替换,只需要局部刷新页面上发生变化的模块,同时可以保留当前的页面状态,比如复选框的选中状态、输入框的输入等。

HMR作为一个Webpack内置的功能,可以通过HotModuleReplacementPlugin或--hot开启。那么,HMR到底是怎么实现热更新的呢?下面让我们来了解一下吧!


webpack的编译构建过程

来源:juejin.cn/post/684490…

项目启动后,进行构建打包,控制台会输出构建过程,我们可以观察到生成了一个 Hash值a93fd735d02d98633356

image.png

然后,在我们每次修改代码保存后,控制台都会出现 Compiling…字样,触发新的编译中...可以在控制台中观察到:

  • 新的Hash值a61bdd6e82294ed06fa3
  • 新的json文件a93fd735d02d98633356.hot-update.json
  • 新的js文件index.a93fd735d02d98633356.hot-update.js

image.png

首先,我们知道Hash值代表每一次编译的标识。其次,根据新生成文件名可以发现,上次输出的Hash值会作为本次编译新生成的文件标识。依次类推,本次输出的Hash值会被作为下次热更新的标识。

然后看一下,新生成的文件是什么?每次修改代码,紧接着触发重新编译,然后浏览器就会发出 2 次请求。请求的便是本次新生成的 2 个文件。如下:

image.png

首先看json文件,返回的结果中,h代表本次新生成的Hash值,用于下次文件热更新请求的前缀。c表示当前要热更新的文件对应的是index模块。

再看下生成的js文件,那就是本次修改的代码,重新编译打包后的。

image.png

还有一种情况是,如果没有任何代码改动,直接保存文件,控制台也会输出编译打包信息的。

  • 新的Hash值d2e4208eca62aa1c5389
  • 新的json文件a61bdd6e82294ed06fa3.hot-update.json

但是我们发现,并没有生成新的js文件,因为没有改动任何代码,同时浏览器发出的请求,可以看到c值为空,代表本次没有需要更新的代码。

小声说下,webapck以前的版本这种情况hash值是不会变的,后面可能出于什么原因改版了。细节不用在意,了解原理才是真谛!!!

最后思考下🤔,浏览器是如何知道本地代码重新编译了,并迅速请求了新生成的文件?是谁告知了浏览器?浏览器获得这些文件又是如何热更新成功的?那让我们带着疑问看下热更新的过程,从源码的角度看原理。

概念

  • webpack Compile:将js文件编译成bundle

  • bundle Server: 提供bundle文件在浏览器端的访问(作为http请求的访问,而不是file文件形式的访问)

  • HMR Server:将热更新的文件发送给HMR Runtime

  • HMR Runtime:会被注入到浏览器的bundle.js文件中(主要作用是在热更新时作为客户端启动websocket和HMR Server进行通信)

  • bundle.js: 编译打包后的js文件

热更新基本流程

image.png

1-2-A-B:文件被编辑,文件系统将文件给webpack Compile编译器进行编译,compile将编译的结果bundle.js发送给Bundle Server,这样浏览器就可以访问BundleServer服务器上的bundle.js文件了。(HMR Runtime 通过 HotModuleReplacementPlugin被注入到bundle.js中)

1-2-3-4-5:此时如果文件被监听到发生变更,文件经过 Webpack-complier 编译好后传输给 HMR ServerHMR Server 知道哪个资源(模块)发生了改变,并通知 HMR Runtime 有哪些变化(也就是上面我们看到的两个请求),HMR Runtime 就会更新我们的代码,这样我们浏览器就会更新并且不需要刷新。

总结

  • HMR Runtime 通过 HotModuleReplacementPlugin 已经注入到我们 chunk 中了

  • webpack-dev-server中除了开启一个 Bundle Server,还开启了 HMR Server,主要用来和 HMR Runtime 中通信

参考

juejin.cn/post/693967…

juejin.cn/post/693967…

juejin.cn/post/684490…

玩转webpack--极客时间