0%

HMR

是什么

HMR 全称是Hot Module Replacement,理解为模块热替换,指在应用程序运行过程中,替换,添加,删除模块,而无需重新刷新整个应用。

例如,我们在应用运行过程中修改了某个模块,通过自动刷新会导致整个应用的整体刷新,那页面中的状态信息都会丢失,如果使用HME,就可以实现只将修改的模块实时替换至应用中,不必完全舒心整个应用。

在webpack中配置热模块:

webpack.config.js

1
2
3
4
5
6
7
const webpack=require('webpack')
module.exports={
...
devServer:{
hot:true
}
}

通过上述这种配置,如果我们修改并保存CSS文件,确实能够以不刷新地形式更新到页面中,但是,当我们修改并保存js文件之后,页面依旧舒刷新了,这里并没有触发热模块,所以,HMR并不像Webpack的其他特性一样可以开箱即用,需要取指定那些模块发生更新时进行HMR

1
2
3
4
5
if(module.hot){
module.hot.accept('./util.js',()=>{
console.log('utils.js更新了')
})
}

实现原理

  • Webpack Compile:将JS源代码编译成bundle.js
  • HMR Server:用来将热更新的文件输出给HMR Runtime
  • Bundle Server:静态资源文件服务器,提供文件访问路径
  • HMR Runtime:socket服务器,会被注入到浏览器,更新文件的变化
  • bundle.js:构建输出的文件
  • 在HMR Runtime和HMR Server之间建立websocket,即图上4号线,用于实时更新文件变化

分成两个阶段:

启动阶段为1-2-A-B

在编写未经过webpack打包的源码后,Webpack Compile将源码和HMR Runtime一起编译成bundle文件,传输Bundle Server静态资源服务器

更新阶段为1-2-3-4

当某一个文件或者模块发生变化时,webpack监听到文件变化对文件重新编译打包,编译生成唯一的hash值,这个hash值用来作为下一次热更新的标识,根据变化的内容生成两个补丁文件:manifest(包含了hash和chunkId,用来说明变化的内容)和chunk.js模块,由于socket服务器在HMR Runtime和HMR Server之间建立websocket链接,单文件发生改动的时候,服务端会向浏览器推送一条消息,消息包含文件改动后生成的hash值,如下图的h属性,做为下一次热更新的标识

在浏览器接收到这条消息之前,浏览器已经在上一次socket消息中记住了此时的hash标识,这时候我们会创建一个ajax去服务端请求获取到变化内容的manifest文件

manifest文件包含重新build生成的hash值,以及变化的模块,对应上图的c属性,浏览器根据manifest文件获取模块变化的内容,从而触发render流程,实现局部模块更新

总结

关于webpack热模块更新总结:

  • 通过webpack-dev-server创建两个服务器,提供静态资源的服务(express)和Socket服务
  • express server负责直接提供静态资源的服务(打包后的资源直接被浏览器请求和解析)
  • socket server是一个websocket的长连接,双方可以通信
  • 当socket server监听到对应的模块发生变化时,会生成两个文件.json(manifest文件)和.js文件(update chunk)
  • 通过长连接,socket server可以直接将这两个文件主动发送给客户端(浏览器)
  • 浏览器拿到两个新的文件后,通过HMR runtime机制,加载这两个文件,并且针对修改的模块进行更新