模塊熱替換(HMR - Hot Module Replacement)作用:是指在應用程序運行過程中替換、添加或刪除模塊,而無需重新加載整個頁面。主要是通過以下幾種方式,來顯著加快開發速度:
- 保留在完全重新加載頁面時丟失的應用程序狀態。
- 只更新變更內容,以節省寶貴的開發時間。
- 調整樣式更加快速 - 幾乎相當於在瀏覽器調試器中更改樣式。
熱更新配置:(在devServer對象裏配置)
webpack.config.js
// 在這裏做打包配置
const path = require('path'); // 引入node的path模塊(loader模塊)
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// 引入熱更新插件,爲webpack中自帶的插件
const webpack = require('webpack');
// Common.js語法
module.exports = {
mode: 'development', // 默認模式爲production,可不寫,不寫時打包運行命令行會有警告
devtool: 'cheap-module-eval-source-map',
entry: {
main: './src/index.js'
},
devServer: {
contentBase: './dist',
open: true,
port: 8080,
hot: true, // 讓webpack-dev-server開啓熱更新的功能
hotOnly: true // 即便是hot配置(HMR)沒有生效,也不讓瀏覽器進行刷新,失效時不做其他處理
},
module: {
rules: [{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
}]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new CleanWebpackPlugin(),
new webpack.HotModuleReplacementPlugin() // 實例化熱更新插件
],
output: {
filename: 'dist.js', // 打包之後的輸出文件
path: path.resolve(__dirname, 'dist')
}
}
// 配置完之後,一定要重新執行打包,不然配置項不會生效
// 樣式文件變化,頁面只修改展示樣式,不會進行頁面的刷新操作,也不會更改之前js操作的內容。
配置項的作用:
- hot: true ===> 讓webpack-dev-server開啓熱更新的功能
- hotOnly: true ===> 即便是hot配置(HMR)沒有生效,也不讓瀏覽器進行刷新 (失效時不做其他處理)
- HotModuleReplacementPlugin爲webpack自帶的熱更新插件,所以要直接引入webpack,在plugins配置項中進行實例化。
熱更新的應用:
在css方面應用:
目錄結構:
|--demo
|--node_modules
|--src
|--index.js
|--style.css
|--index.html
|--package.json
|--package-lock.json
|--webpack.config.js
src/style.css
div:nth-of-type(odd) {
background: #2086d7;
}
src/index.js
import './style.css';
var btn = document.createElement('button');
btn.innerHTML = '新增';
document.body.appendChild(btn);
btn.onclick = function() {
var div = document.createElement('div');
div.innerHTML = 'item';
document.body.appendChild(div);
}
執行打包:
npm run start
頁面展示效果如圖:(點擊新增按鈕,新增item項之後的效果)
此時,再去修改style.css裏的樣式:(把偶數行的背景色改爲粉色)
div:nth-of-type(odd) {
background: pink;
}
頁面展示效果爲:(沒有刷新瀏覽器,只更改了樣式)
如果不開啓熱更新,修改樣式之後,由於瀏覽器刷新,頁面會恢復到初始狀態,頁面上只保留一個"新增"按鈕,再去點擊的時候,纔會有不同顏色的item顯示在頁面中。
在js方面的應用:
目錄結構:
|--demo
|--node_modules
|--src
|--counter.js
|--number.js
|--index.js
|--index.html
|--package-lock.json
|--package.json
|--webpack.config.js
counter.js
function counter() {
var div = document.createElement('div');
div.setAttribute('id', 'counter');
div.innerHTML = 1;
div.onclick = function() {
div.innerHTML = parseInt(div.innerHTML, 10) + 1
}
document.body.appendChild(div);
}
export default counter;
number.js
function number() {
var div = document.createElement('div');
div.setAttribute('id', 'number');
div.innerHTML = 1000;
document.body.appendChild(div);
}
export default number;
index.js
import counter from './counter';
import number from './number';
counter();
number();
// 這裏需要判斷下是否開啓了熱更新,如果開啓了,就只讓number函數再執行一次,否則不會熱更新
if(module.hot) {
module.hot.accept('./number', () => {
document.body.removeChild(document.getElementById('number'));
number();
})
}
本質上要實現HMR,都要寫類似以上(判斷是否開啓熱更新,單獨執行某代碼塊)的代碼,否則不會熱更新。但在很多時候,我們開發過程中,並沒有去寫這樣的代碼,是因爲在相應的loader中,已經幫我們實現了熱更新的代碼。如:
- css-loader中同樣也配置了熱更新,也不需要自己額外添加代碼
- 我們使用的vue框架裏,vue-loader裏也已經配置了熱更新,所以不需要額外添加代碼
index.js中引入兩個模塊,如果不開啓熱更新,那麼當一個模塊裏的數據變化了,就會導致頁面刷新,使另一個模塊內的數據也恢復到初始值,如果我們想一個模塊裏的js代碼的變化,不影響另一個模塊代碼變更過的數據,每改一個js模塊裏的代碼,只會更新當前模塊的數據,不會影響其他js模塊的數據。以上需求可藉助HMR來實現,
執行打包:
npm run start
頁面展示效果:(第一行數字帶有點擊事件,初始值爲1,每點擊一次數值會加1)
當點擊數字值增加爲7時,去修改number.js模塊裏的代碼,把1000修改爲3000,此時頁面不刷新,counter.js模塊裏的數字7也沒有變化,只更改了當前模塊修改的數據。如下圖:
這就是熱更新的巧妙之處。? (如果不開啓熱更新,修改number.js裏的代碼後,由於頁面會刷新,counter.js裏的數字也會變成初始值1)