模块热替换
定义
模块热替换(HMR - hot module replacement)功能会在应用程序运行过程中,替换、添加或删除模块,而无需重新加载整个页面。
- 保留应用程序状态
- 只更新变更内容
- 源码中修改css/js时,会立刻在浏览器中更新
[扩展]module、chunk和boundle的区别
- module: 每个通过import,require,@import引入的文件都是一个module
- chunk: 用来管理构建过程的中间量,是由一个或多个module组成,一般情况下,分为入口chunk(entryChunk)和子chunk(split chunk)和import动态加载模块都是一个chunk
- boundle: 打包生成的文件,一般来说一个chunk匹配一个boundle,主要取决于具体的配置
模块API
if (module.hot) {
module.hot.accept('./library.js', function() {
// 对更新过的 library 模块做些事情...
});
}
如果启用了热更新,则它的接口将被暴露在module.hot
- accept,接受accept给定的依赖模块的更新,并触发一个回调函数来响应更新,除此之外,你可以附加一个可选的error处理程序
module.hot.accept(
dependencies, // 可以是一个字符串或字符串数组
callback // 用于在模块更新后触发的函数
errorHandler // (err, {moduleId, dependencyId}) => {}
);
- check: 测试所有加载的模块以进行更新,如果有更新则应用他们
module.hot
.check(autoApply)
.then((outdatedModules) => {
// 超时的模块...
})
.catch((error) => {
// 捕获错误
});
效果展示
- 热更新基础效果展示【见代码】
-
说明
-
当文件修改的时候,在network中我们可以看到两个请求
- 第一个是hash.hot-update.json,返回一个新的hash和change的chunkId
- 第二个是chunk.hash.hot-update.js文件,以jsonp的形式返回一个方法调用,第一个参数是chunkId,第二个参数是一个对象,以键值队的形式返回被更新的文件也就是moduleId和它更新后的模块内容
- 执行回调函数,模块更新
-
工作原理
- 热更新原理展示【配合代码和下图】
- 代码(见下篇)
webpack实现热更新效果的时候主要有上图几个方面协同作用
服务端:
- 如图创建webpack实例
- 创建server服务器,并建立websocket连接
- 添加done事件回调
- compiler.watch监听到文件发生变化,进行重新编译
- 编译完成之后触发done钩子,websocket向客户端(即)浏览器端发送hash和ok事件
客户端(浏览器端)
-
连接websocket
-
热模块方法为module添加parent、children、hot和accept()和check()方法
-
websocket监听事件
-
websocket监听到hash和ok事件
- hash事件中,将hash保存为currentHash
- ok事件中,会触发webpackHotUpdate事件
热更新模块(合并HotModuleReplacement.runtime和webpack/hot/dev-server文件)
webpack/hot/dev-server文件
-
监听到webpackHotUpdate事件
-
执行hotCheck方法
- 发送lashHash.hot-update.json请求,告知新的hash和被更改的chunk
- 即{"h":"99a3d7248ecb0dbf2410","c":{"main":true}}
-
拿到被更改的chunk后执行hotDownloadUpdateChunk方法
- 使用jsonp方式发送请求chunkId.lastHash.hot-update.js
- 返回更新后的模块内容,并用webpackHotUpdate方法包裹,该方法可以直接执行
-
移除旧的模块,从父模块找到该模块的accept接收的回调方法
-
执行回调方法
-
更新完成