Skip to main content

HMR 模块热替换 - 热重载

一、HMR 的定义

模块热替换(HMR - hot module replacement)是指在页面运行的过程中更新各种模块时,无需重新加载整个页面。

HMR 主要是通过以下几种方式,来加快开发速度:

  • 保留在重新加载页面期间丢失的应用程序状态;
  • 只更新变更的内容,节省编译时间;
  • 在源代码中修改 CSS/JS 时,会立刻在浏览器中进行更新,这几乎相当于在浏览器 devtools 直接更改样式。

注意:HMR 不适用于生产环境,这意味着它应当只在开发环境使用。

二、HMR 的启用

默认情况下,webpack-dev-server 已支持 HMR,只需要开启即可。

首先安装 webpack-dev-server 服务器插件:

npm install webpack-dev-server --save-dev

package.json 中的启动命令添加 webpack-dev-server

package.json
{
// ...
"scripts": {
"start": "webpack-dev-server"
},
// ...
}

在不开启 HMR 的情况下,修改了源代码后整个页面会自动刷新,使用的是 live reloading,下面是启用 HMR:

首先在入口文件(src/index)添加以下代码:

if (module.hot) {
module.hot.accept(function () {
console.log('Accepting the updated printMe module!')
})
}

然后启用 HMR,有两种方式可以启用:

1、设置配置文件的方式

webpack.config.js 中添加 devServer 选项,并设置 hot 值为 true 即可启用 HMR:

webpack.config.js
const path = require('path')

module.exports = {
entry: './index.js',
output: {
filename: 'bundle.js',
path: path.join(__dirname, '/')
},
devServer: {
hot: true, // 启动模块热更新 HMR
},
}

点击查看更多 webpack-dev-server 配置项

2、命令行配置的方式

另一种启用 HMR 的方式是通过在启动命令添加 --hot 参数来实现,常搭配 --open 来自动打开浏览器到页面:

package.json
{
// ...
"scripts": {
"start": "webpack-dev-server"
"start": "webpack-dev-server --hot --open"
},
// ...
}

3、React 中配置 HMR 的方式

注意:通过上面直接开启 HMR 的方式也可以实现。

React Hot Loader 可以实现 React 的 HMR,但已被 React Fast Refresh 所取代。

React-Hot-Loader is expected to be replaced by React Fast Refresh. Please remove React-Hot-Loader if Fast Refresh is currently supported on your environment.

安装:

# npm
npm install -D @pmmmwh/react-refresh-webpack-plugin react-refresh

# yarn
yarn add -D @pmmmwh/react-refresh-webpack-plugin react-refresh

# pnpm
pnpm add -D @pmmmwh/react-refresh-webpack-plugin react-refresh

点击查看使用详情

4、Vue 中配置 HMR 的方式

Vue Loader 支持用于 vue 组件的 HMR,提供开箱即用体验。

安装:

npm install vue-loader -D

使用:

vue-loader 加载的组件默认进行 HMR 的处理,直接在 webpack 配置文件中添加即可,最新版本的 vue-loader 已不需要通过 require('vue-loader/lib/plugin') 的方式引入了:

webpack.config.js
const { VueLoaderPlugin } = require('vue-loader')

module.exports = {
devServer: {
hot: true
},

module: {
rules: [
{
test: /\.vue$/,
use: 'vue-loader'
}
]
},

plugins: [
new VueLoaderPlugin()
]
}

三、模块热替换的原理

webpack-dev-server 会创建两个服务器:提供静态资源的服务(express)和 Socket 服务。

其中 HMR Server 是一个 WebSocket 的长连接,长连接的好处就是建立连接后双方可以通信。当 HMR Server 监听到对应的模块发生变化时,会生成一个 manifest 的 JSON 文件记录更新的位置等配置信息,还有一个 update chunk 的 JS 文件记录实际更新的具体内容;

通过长连接,HMR Server 可以直接将这两个文件主动发送给浏览器;

浏览器拿到两个新文件后,通过 HMR runtime 机制(webpack 打包时提供)加载这两个文件,并且针对修改的模块进行更新。

点击查看 HMR 实现详细过程