webpack中的HMR


本文作者: jsweibo

本文链接: https://jsweibo.github.io/2019/07/11/webpack%E4%B8%AD%E7%9A%84HMR/

摘要

本文主要讲述了:

  1. 什么是 HMR
  2. JavaScript
  3. CSS

正文

什么是 HMR

启动webpack-dev-server之后,当模块内容发生变化时,webpack-dev-server默认情况下会自动进行完全重载。项目小的时候这样做还不影响性能,但是当项目变大之后,每次完全重载可能需要花费过多的时间。由此 HMR 应运而生。

HMR,全称为 Hot Module Replacement(热模块替换)。

HMR 指的是,不需要完全重载,只需要更新变化了的部分。

注意:

  1. HMR 只适用于开发环境而不适用于生产环境
  2. 不要在开发环境的配置文件中配置[hash][chunkhash]等文件名占位符,这很可能会导致内存泄漏

JavaScript

示例:

learn_webpack/webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
devServer: {
hot: true,
},
plugins: [
new HtmlWebpackPlugin({
title: 'learn_webpack',
template: 'public/index.html',
}),
],
};

learn_webpack/public/index.html

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body></body>
</html>

learn_webpack/src/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import printMe from './print.js';

function component() {
const element = document.createElement('div');
const btn = document.createElement('button');

element.innerHTML = 'hello, jsweibo';

btn.innerHTML = 'Click me and check the console!';
btn.onclick = printMe;

element.appendChild(btn);

return element;
}

let element = component();
document.body.appendChild(element);

if (module.hot) {
module.hot.accept('./print.js', function () {
console.log('Accepting the updated printMe module!');
});
}

learn_webpack/src/print.js

1
2
3
module.exports = function () {
console.log('print me!');
};

devServer 启动后,如果修改print.js,例如下面这样:

learn_webpack/src/print.js

1
2
3
module.exports = function () {
console.log('print me, please!');
};

此时 HMR 将被触发。

但是,此时<button>点击事件的回调函数依然在旧的print.js上。因此,还需要对index.js做一点修改。

learn_webpack/src/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import printMe from './print.js';

function component() {
const element = document.createElement('div');
const btn = document.createElement('button');

element.innerHTML = 'hello, jsweibo';

btn.innerHTML = 'Click me and check the console!';
btn.onclick = printMe;

element.appendChild(btn);

return element;
}

let element = component();
document.body.appendChild(element);

if (module.hot) {
module.hot.accept('./print.js', function () {
console.log('Accepting the updated printMe module!');

// 移除受影响的DOM并重新渲染
document.body.removeChild(element);
element = component();
document.body.appendChild(element);
});
}

CSS

CSS 的 HMR 比起 JavaScript 要简单很多,因为 loader 已经替我们做了大量的工作。

learn_webpack/webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
devServer: {
hot: true,
},
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
},
],
},
],
},
plugins: [
new HtmlWebpackPlugin({
title: 'learn_webpack',
template: 'public/index.html',
}),
],
};

learn_webpack/src/index.js

1
import './css/style.css';

learn_webpack/src/css/style.css

1
2
3
body {
color: #f00;
}

devServer 启动后,如果修改style.css,例如下面这样:

learn_webpack/src/css/style.css

1
2
3
body {
color: #ff0;
}

此时 HMR 将被触发。

参考资料

本文作者: jsweibo

本文链接: https://jsweibo.github.io/2019/07/11/webpack%E4%B8%AD%E7%9A%84HMR/


本文对你有帮助?请支持我


支付宝
微信