是什么
HMR 全称是Hot Module Replacement,理解为模块热替换,指在应用程序运行过程中,替换,添加,删除模块,而无需重新刷新整个应用。
例如,我们在应用运行过程中修改了某个模块,通过自动刷新会导致整个应用的整体刷新,那页面中的状态信息都会丢失,如果使用HME,就可以实现只将修改的模块实时替换至应用中,不必完全舒心整个应用。
在webpack中配置热模块:
webpack.config.js
1 | const webpack=require('webpack') |
通过上述这种配置,如果我们修改并保存CSS文件,确实能够以不刷新地形式更新到页面中,但是,当我们修改并保存js文件之后,页面依旧舒刷新了,这里并没有触发热模块,所以,HMR并不像Webpack的其他特性一样可以开箱即用,需要取指定那些模块发生更新时进行HMR
1 | if(module.hot){ |
实现原理
- 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机制,加载这两个文件,并且针对修改的模块进行更新