模块热替换
模块热替换(Hot Module Replacement 或 HMR)是 webpack 提供的最有用的功能之一。它允许在运行时更新各种模块,而无需进行完全刷新。本页面重点介绍实现,而概念页面提供了更多关于它的工作原理以及为什么它有用的细节。
HMR 不适用于生产环境,这意味着它应当只在开发环境使用。更多详细信息,请查看生产环境构建指南。
启用 HMR
启用此功能实际上相当简单。我们来看看如何使用 webpack-dev-server 来设置 HMR……
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: './index.js',
plugins: [
new webpack.HotModuleReplacementPlugin() // 启用 HMR
],
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/'
},
devServer: {
hot: true, // 告诉 dev-server 我们在使用 HMR
contentBase: path.resolve(__dirname, 'dist'),
publicPath: '/'
}
};
不是太坏,嗯?我们使用 module.hot.accept
来测试一下……
index.js
import Library from './library';
if (module.hot) {
module.hot.accept('./library', function() {
console.log('Accepting the updated library module!');
Library.log();
})
}
library.js
export default {
log() {
// 在服务器启动后进行修改以进行测试
console.log('Initial log...')
}
}
开始将 library.js
中的 console.log
语句,改为 Second log...'
,你应该在浏览器控制台中看到如下输出:
[HMR] Waiting for update signal from WDS...
main.js:9998 Initial log...
main.js:9468 [WDS] Hot Module Replacement enabled.
+ 2main.js:9468 [WDS] App updated. Recompiling...
+ main.js:9468 [WDS] App hot update...
+ main.js:9912 [HMR] Checking for updates on the server...
+ main.js:9982 Accepting the updated library module!
+ 0.1bafc70….hot-update.js:11 Second log...
+ main.js:9955 [HMR] Updated modules:
+ main.js:9957 [HMR] - ./src/library.js
+ main.js:9894 [HMR] App is up to date.
问题
热模块更换可能很难掌握。例如,假设我有以下 class 类:
class Logger {
log(text) {
console.log('Logging some text: ', text)
}
}
即使包含此 class 类的底层模块已使用新代码进行修补(patch),任何现有的类实例仍然具有旧的 log
方法。也就是说,如果我们修改这个方法内部,那么旧的实例就不会被反映出来,除非我们以使用 module.hot.accept
的方式重新实例化它们。
这只是一个例子,但还有很多其他人可以轻松地让人犯错的地方。幸运的是,有很多 loader 在,一些会在下面提到,这将使这个使用过程变得更容易。
HMR 修改样式表
在 style-loader
的帮助下,模块热替换(Hot Module Replacement)修改 CSS 实际上相当简单。当更新 CSS 依赖模块时,此 loader 在后台使用 module.hot.accept
来修补(patch) <style>
标签。所以,可以使用以下 webpack 配置...
module.exports = {
// ...
module: {
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}
]
},
// ...
}
热加载样式表轻而易举……
index.js
import Lib from './library';
import './styles.css';
// ...
styles.css
body {
background: blue;
}
将 body
上的样式修改为 background: red;
,您应该可以立即看到页面的背景颜色随之更改,而无需完全刷新。
其他代码和框架
社区还有许多其他 loader 和示例,可以使 HMR 与各种框架和库(library)平滑地进行交互……
- React Hot Loader:实时调整 react 组件。
- Vue Loader:此 loader 支持用于 vue 组件的 HMR,提供开箱即用体验。
- Elm Hot Loader:支持用于 Elm 程序语言的 HMR。
- Redux HMR:无需 loader 或插件!只需对 main store 文件进行简单的修改。
如果你知道任何其他 loader 或插件,能够有助于或增强模块热替换(Hot Module Replacement),请提交一个 pull request 以添加到此列表中!