模块热更新(Hot Module Replacement 或 HMR)是 webpack 提供的最有用的功能之一。它允许在运行时更新各种模块,而无需进行完全刷新。
启用 HMR
启用此功能实际上相当简单。而我们要做的,就是更新 webpack-dev-server 的配置,和使用 webpack 内置的 HMR 插件。
webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const webpack = require('webpack')
module.exports = {
mode: 'development',
devtool: 'source-map',
devServer: {
contentBase: './dist',
open: true,
port: 8080,
hot: true,
hotOnly: true
},
module: {
rules: [
{
test:/\.css$/,
use: [
'style-loader',
'css-loader'
]
},
]
},
entry: {
app: './src/index.js',
// print: './src/print.js'
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
//publicPath也会在服务器脚本用到,确保资源能够在 http://localhost:3000下正确访问
publicPath: '/'
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new CleanWebpackPlugin(),
new webpack.HotModuleReplacementPlugin() //要先引入webpack,是webpack自带的插件
]
}
记得添加处理css文件的规则并重新安装css-loader 和 style-loader:
npm install --save-dev css-loader style-loader
src/index.js
// import print from './print'
import './style.css'
// var dom = document.getElementById("root")
// var btn = document.createElement("button")
// btn.innerHTML = "click me"
// btn.onclick = print
// dom.appendChild(btn)
var btn2 = document.createElement("button")
btn2.innerHTML = "新增"
btn2.onclick = function() {
var div = document.createElement("div")
div.innerHTML = 'item'
document.body.appendChild(div)
}
document.body.appendChild(btn2)
在src目录下新建style.css文件
src/style.css
div:nth-of-type(odd) {
background: yellow;
}
在命令行中运行 npm start
来启动并运行 dev server
点击新增按钮添加item,页面显示如下:
然后修改src/style.css中样式颜色:
div:nth-of-type(odd) {
background: purple;
}
页面不需要再次点击显示如下,直接更新了样式:
总结: 改变样式,只会改变页面样式内容,不会改变之前js渲染出来的内容,方便样式调试。
那如果是js文件的情况
在src目录下新建number.js和counter.js
src/number.js
function number() {
var div = document.createElement("div")
div.setAttribute('id', 'number')
div.innerHTML = "2000"
document.body.appendChild(div)
}
export default number
src/counter.js
function counter() {
var div = document.createElement("div")
div.innerHTML = 1
div.setAttribute('id', 'counter')
div.onclick = function() {
div.innerHTML = parseInt(div.innerHTML, 10) + 1
}
document.body.appendChild(div)
}
export default counter
src/index.js
import counter from './counter'
import number from './number'
counter()
number()
在命令行中运行 npm start
来启动并运行 dev server
页面显示如下:
点击1位置一直加1
而当我们修改number.js文件中div.innerHTML = "3000"
重新刷新页面时,页面显示如下:
这里的问题是重新刷新,更新其中一模块影响到了另一模块
解决方法:实现html都得写module.hot.accept代码
但是像前面css文件,它的插件如css-loader已经帮助我们实现了下面的代码就不需要再写
src/index.js
import counter from './counter'
import number from './number'
counter()
number()
if(module.hot) {
module.hot.accept('./number.js', function(){
document.body.removeChild(document.getElementById("number"))
number()
})
}
重新刷新页面,发现更改number.js文件中div.innerHTML = "3000"
,
并不会影响counter.js文件
页面显示为: