一、是什么
HMR
全称 Hot Module Replacement
,可以理解为模块热替换,指在应用程序运行过程中,替换、添加、删除模块,而无需重新刷新整个应用
例如,我们在应用运行过程中修改了某个模块,通过自动刷新会导致整个应用的整体刷新,那页面中的状态信息都会丢失
如果使用的是 HMR
,就可以实现只将修改的模块实时替换至应用中,不必完全刷新整个应用
在webpack
中配置开启热模块也非常的简单,如下代码:
const webpack = require('webpack')
module.exports = {
// ...
devServer: {
// 开启 HMR 特性
hot: true
// hotOnly: true
}
}
通过上述这种配置,如果我们修改并保存css
文件,确实能够以不刷新的形式更新到页面中
但是,当我们修改并保存js
文件之后,页面依旧自动刷新了,这里并没有触发热模块
所以,HMR
并不像 Webpack
的其他特性一样可以开箱即用,需要有一些额外的操作
我们需要去指定哪些模块发生更新时进行HRM
,如下代码:
if(module.hot){
module.hot.accept('./util.js',()=>{
console.log("util.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
和 chundId
,用来说明变化的内容)和chunk.js
模块
由于socket
服务器在HMR Runtime
和 HMR Server
之间建立 websocket
链接,当文件发生改动的时候,服务端会向浏览器推送一条消息,消息包含文件改动后生成的hash
值,如下图的h
属性,作为下一次热更细的标识
在浏览器接受到这条消息之前,浏览器已经在上一次socket
消息中已经记住了此时的hash
标识,这时候我们会创建一个 ajax
去服务端请求获取到变化内容的 manifest
文件
mainfest
文件包含重新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机制,加载这两个文件,并且针对修改的模块进行更新
Webpack的热更新(Hot Module Replacement,简称HMR)是指在应用程序运行时,无需刷新整个页面,只更新发生更改的模块。HMR的原理如下:
- 当开发者启用HMR功能并运行Webpack时,Webpack会在输出的包中添加一些HMR运行时代码。这些代码负责与开发服务器建立WebSocket连接,并接收来自服务器的更新通知。
- 当开发者修改了一个模块时,Webpack会生成一个更新补丁(update patch)。这个补丁包含了模块发生更改的详细信息。
- HMR运行时代码会接收到更新补丁,并通过Webpack的模块系统应用更新。它会找到发生更改的模块,替换旧的模块,并触发相应的回调函数。
- 在处理完模块的更改后,HMR运行时代码会通知Webpack完成热更新过程。Webpack会通知开发服务器将更新发送给浏览器客户端。
- 浏览器客户端接收到更新后,使用新的模块来替换页面中发生更改的部分,从而实现热更新,而不需要刷新整个页面。
总结来说,Webpack的热更新通过在开发服务器和浏览器客户端之间建立WebSocket连接,将模块更改的信息传递给浏览器,并在浏览器中实现局部更新,提高开发效率。
三、总结
热重载(Hot Module Replacement,HMR)是Webpack提供的一项功能,它允许在开发过程中,无需刷新整个页面,即可实时更新修改的模块。
通过热重载,可以提高开发效率,快速查看代码变化的结果,并保持应用的状态(如表单数据)。
要配置实现热更新,需要进行以下步骤:
- 在
Webpack
配置文件中启用热模块替换。可通过配置devServer.hot
选项为true
来启用HMR:
// webpack.config.js
module.exports = {
// ...
devServer: {
hot: true,
},
};
- 在入口文件中添加对HMR的支持。在入口文件中,需要添加HMR的逻辑以监听模块的变化,并告诉Webpack如何处理更新。
// index.js
if (module.hot) {
module.hot.accept();
}
- 配置Webpack插件。HMR需要搭配相应的插件使用,常用的是
webpack.HotModuleReplacementPlugin
。
// webpack.config.js
const webpack = require('webpack');
module.exports = {
// ...
plugins: [
new webpack.HotModuleReplacementPlugin(),
// ...其他插件
],
};
完成上述配置后,运行Webpack开发服务器时,Webpack
会在文件发生变化时将更新的模块代码发送给浏览器,浏览器会在不刷新整个页面的情况下,替换掉相应的模块。
注意❗
请注意,热重载只适用于开发环境,并不能直接用于生产环境。在生产环境中,需要使用Webpack生成的静态文件进行部署。
热重载可以提高开发效率,但在某些情况下可能会遇到一些问题,如状态丢失、事件绑定问题等。因此,对于某些情况下,可能需要手动刷新页面来确保正确的状态。