前言
之前更新过一篇Webpack文章:Webpack入门只看这一篇就够了(图文+代码),没想到颇受好评,很快就阅读量就破万了hhh,应读者私信的要求,决定继续更新Webpack进阶系列的文章!
进入今天的主题 ------ HMR
热模块替换(HotModuleReplacement)
开发时我们修改了其中一个模块代码,Webpack 默认会将所有模块全部重新打包编译,速度很慢。所以我们需要做到修改某个模块代码,就只有这个模块代码需要重新打包编译,其他模块不变,这样打包速度就能很快。
HotModuleReplacement (HMR/热模块替换) 的作用就是在程序运行中,替换、添加或删除模块,而 无需重新加载整个页面。
使用场景

如上图所示,一个注册页面包含用户名、密码、邮箱三个必填输入框,以及一个提交按钮,当你在调试邮箱模块改动了代码时,没做任何处理情况下是会刷新整个页面 ,频繁的改动代码会浪费你大量时间去重新填写内容。预期是保留用户名、密码的输入内容,而只替换邮箱这一模块。这一诉求就需要借助webpack-dev-server的热模块更新功能。
相对于live reload整体刷新页面 的方案,HMR的优点在于可以保存应用的状态,提高开发效率。
代码实操
热替换只能用于开发环境,生产环境是不需要的,且开发环境中hot配置默认是开启的。
javascript
// webpack.dev.js
devServer: {
host: "localhost", // 启动服务器域名
port: "3000", // 启动服务器端口号
open: true, // 是否自动打开浏览器
hot: true, // 开启HMR功能
},
在hot:true的情况下运行开发环境,如下更改css的时候可以看到页面并没有刷新,而只是对更改的css进行了解析,因为我们在开发模式下使用的style-loader实现了这一功能,这就是热模块替换

虽然css实现了热模块替换,但JS还没有实现,更改JS文件进行保存还是会刷新页面重新打包编译,JS实现热模块替换还需要进行下面的操作:
javascript
// src/main.js
// 判断是否支持HMR功能
if (module.hot) {
module.hot.accept("./js/count.js");
}
加上这个count.js改变之后就会进行热模块替换,如果其他文件也需要进行热模块替换也是需要加上module.hot.accept("");进行设置。
module.hot.accept("./js/count.js",function(){});还可以接收一个函数,这个函数就是当触发热替换的时候就会自动调用这个函数。
当然,如果文件很多的话会很麻烦,在实际开发中会使用其他的loader来解决这个问题,比如vue-loader
原理

如上图所示,右侧Server端使用webpack-dev-server去启动本地服务,内部实现主要使用了webpack、express、websocket。
-
使用
express启动本地服务,当浏览器访问资源时对此做响应。 -
服务端和客户端使用
websocket实现长连接 -
webpack监听源文件的变化,即当开发者保存文件时触发webpack的重新编译。 -
每次编译都会生成
hash值、已改动模块的json文件、已改动模块代码的js文件,编译完成后通过socket向客户端推送当前编译的hash戳 -
客户端的
websocket监听到有文件改动推送过来的hash戳,会和上一次对比一致则走缓存,不一致则通过ajax和jsonp向服务端获取最新资源 -
使用
内存文件系统去替换有修改的内容实现局部刷新
oneOf
在运行打包代码时每个文件都会经过所有loader处理,虽然因为test正则原因实际没有处理上,但是都要走,如果loader和文件很多,那就会大大拖慢打包文件的速度,那么就可以使用oneOf,也就是只能匹配上一个 loader, 只要匹配到了剩下的就不匹配了。
使用:
我们只需要在生产环境和开发环境的配置中将所有的规则像下面这样包起来就可以了:
javascript
rules:[
{
oneOf:[
将原本卸载rules:[]的规则放进来!
]
}
]
完成上面的操作之后分别在开发模式和生产模式进行一次代码的打包,测试一下打包是否可以成功,成功则说明配置是正确的,虽然能优化的速度有限,但蚊子再小也是肉也是不错的!