webpack 热替换 HMR

664

什么是热替换?

热替换(Hot Module Replacement)指的是当我们在开发模式下使用webpack构建一个项目时,当我们改动项目文件中的代码,不仅webpack要重新构建,并且浏览器也要同步更新页面。所以热替换并不能降低构建的时间,而是降低代码改动到效果呈现的时间。

当使用webpack-dev-server时,考虑代码更新到效果呈现的过程

graph TD
代码变动 --> 重新打包 --> 浏览器刷新请求所有资源 --> 浏览器执行代码 -->|监控| 代码变动

使用热替换,流程就发生了改变

graph TD
代码变动 --> 重新打包 --> 浏览器仅请求改变资源 --> 浏览器执行代码 -->|监控| 代码变动

HMR主要做的就算避免每次更改代码导致浏览器重新刷新。

使用和原理

更改配置

    module.exports = {
         devserver: {
            hot: true //开启HMR
        },
        plugins: [
            new webpack.HotModuleReplacementPlugin() //可选
        ]
    }

更改代码

    //index.js
    if(module.hot){ //是否开启热更新
        module.hot.accept() //接受热更新
    }

注:上述代码的module是哪里来的呢?我们知道打包后的代码是放在函数 function(module,exports,_webpack_require_){}中运行的,所以这个module也是该函数提供的

首先上面这段代码会参与最终的运行 当开启了热更新后,webpack-dev-server会向打包结果中注入module.hot属性,默认情况下,webpack-dev-server不管受否开启热更新,当重新打包后,都会调用location.reload来刷新页面。但是如果运行了modlue.hot.accept(),则将改变这一行为。 module.hot.accept()的作用是让服务器把更新的内容发送到浏览器。

然而基于http协议是做不到服务器主动发送信息给浏览器的,这个时候就需要用到WebSocket,基于WebSocket,这样webpack-dev-server就可以在代码更新后主动将最新的资源发送给浏览器。

graph TD
浏览器 -->|web socket| 服务器 -->|web socket|浏览器

然后再将结果交给插件HotModuleReplacementPlugin注入的代码执行,插件HotModuleReplacementPlugin会根据覆盖原始代码,然后让代码重新执行。

所以热替换发生在代码运行期间

样式热替换

对于样式,也是可以使用热替换的,不过需要 使用style-loader,因为发生热替换时,HotModuleReplacementPlugin只会简单地重新运行模块代码,因此style-loader的代码一运行就会重新设置style元素中的样式。而mini-css-extrat-plugin,由于它生成文件是在构建期间,运行期间无法改动文件,因此它对于热替换是无效的。