webpack學習(七):啟用 HMR(模組熱替換)
demo地址: https://github.com/Lkkkkkkg/webpack-demo
上次使用 webpack-dev-serve : https://blog.csdn.net/qq593249106/article/details/84922572
當前目錄結構 :
|- /dist //用於放打包後文件的資料夾
|- app.bundle.js //出口檔案
|- print.bundle.js //出口檔案
|- index.html //模板檔案
|- /node_modules
|- /src //用於放原始檔的資料夾
|- index.js //入口檔案
|- print.js
| - package.json
|- webpack.config.js //webpack配置檔案
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js'
// print: './src/print.js'
},
devtool: 'inline-source-map', // 不同選項適用於不同環境
devServer: {
contentBase: './dist', //將dist目錄下的檔案(index.html)作為可訪問檔案, 如果不寫這個引數則預設與webpack.cofig.js的同級目錄
port: 8080 //埠號設為8080, 預設也是8080
},
plugins: [ //webpack 通過 plugins 實現各種功能, 比如 html-webpack-plugin 使用模版生成 html 檔案
new CleanWebpackPlugin (['dist']), //設定清除的目錄
new HtmlWebpackPlugin({
filename: 'index.html', //設定生成的HTML檔案的名稱, 支援指定子目錄,如:assets/admin.html
title: 'Form HtmlWebpackPlugin', //設定生成的HTML的title
})
],
output: {
filename: '[name].bundle.js', //根據入口檔案輸出不同出口檔案
path: path.resolve(__dirname, 'dist')
}
};
這裡把配置的 入口檔案 print.js 給去掉了, 因為 print.js 被 入口檔案 index.js 應用了
HMR(模組熱替換)
模組熱替換(Hot Module Replacement 或 HMR)是 webpack 提供的最有用的功能之一, 它允許在執行時更新各種模組, 而無需進行完全重新整理
比如在這個現在修改 print.js 裡面的內容, 使用 HMR 就可以只更新 print.js 裡面的內容而不用重新加在整個頁面
啟用HMR
啟用這個功能很簡答, 只需要修改一下 webpack.config.js 的配置, 使用 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'); //引入 webpack
module.exports = {
entry: {
app: './src/index.js'
// print: './src/print.js'
},
devtool: 'inline-source-map', // 不同選項適用於不同環境
devServer: {
contentBase: './dist', //將dist目錄下的檔案(index.html)作為可訪問檔案, 如果不寫這個引數則預設與webpack.cofig.js的同級目錄
port: 8080, //埠號設為8080, 預設也是8080,
hot: true
},
plugins: [ //webpack 通過 plugins 實現各種功能, 比如 html-webpack-plugin 使用模版生成 html 檔案
new CleanWebpackPlugin(['dist']), //設定清除的目錄
new HtmlWebpackPlugin({
filename: 'index.html', //設定生成的HTML檔案的名稱, 支援指定子目錄,如:assets/admin.html
title: 'Form HtmlWebpackPlugin', //設定生成的HTML的title
}),
new webpack.HotModuleReplacementPlugin() //啟用 webpack 內建的 HMR外掛
],
output: {
filename: '[name].bundle.js', //根據入口檔案輸出不同出口檔案
path: path.resolve(__dirname, 'dist')
}
};
啟用 webpack 內建的 HMR外掛後, module.hot 介面就會暴露在 index.js 中, 接下來需要在 index.js 中配置告訴 webpack 接受HMR的模組( print.js ):
index.js
import _ from 'lodash';
import printMe from './print.js';
function component() {
var element = document.createElement('div');
var btn = document.createElement('button'); //新建一個button物件
element.innerHTML = _.join(['Hello', 'webpack'], ' '); //要用到lodash的語法
btn.innerHTML = 'Click me and check the console!';
btn.onclick = printMe; //button觸發的事件是引用的print.js暴露的事件
element.appendChild(btn); //把button物件插入div中
return element;
}
document.body.appendChild(component());
if (module.hot) {
module.hot.accept('./print.js', function() { //告訴 webpack 接受熱替換的模組
console.log('Accepting the updated printMe module!');
printMe();
})
}
啟動 webpack-dev-server
終端輸入 npm run dev 啟動, 開啟 index.html, 然後去修改 print.js 裡面的內容:
print.js
export default function printMe() {
//console.log('I get called from print.js!');
console.log('change');
}
回到網頁看控制檯:
可以看到 HMR 的字眼, 並且看到了 index.js下的輸出(‘Accepting the updated printMe module!’) 和 print.js 修改後的輸出(‘change’), 說明伺服器檢測到了 print.js 的程式碼變化並且執行了 module.hot.accept 的回撥函式,
但是現在只成功了50%, 因為點選 button 按鈕, 會發現輸出還是之前的(‘I get called from print.js!’), 說明 print.js 雖然被修改了, 但在 index.js 上還沒有被修改之後的替換, 所以 button 繫結的還是之前的事件, 這裡需要在檢測到程式碼修改後, 用修改之後的js重新渲染頁面:
index.js
import _ from 'lodash';
import printMe from './print.js';
function component() {
var element = document.createElement('div');
var btn = document.createElement('button'); //新建一個button物件
element.innerHTML = _.join(['Hello', 'webpack'], ' '); //要用到lodash的語法
btn.innerHTML = 'Click me and check the console!';
btn.onclick = printMe; //button觸發的事件是引用的print.js暴露的事件
element.appendChild(btn); //把button物件插入div中
return element;
}
var element = component(); //改用一個element儲存一下
document.body.appendChild(element);
if (module.hot) { //告訴 webpack 接受熱替換的模組
module.hot.accept('./print.js', function() {
console.log('Accepting the updated printMe module!');
document.body.removeChild(element); //刪掉舊的element
element = component(); //獲得一個修改後的element
document.body.appendChild(element); //重新插入到網頁中
})
}
熱過載
因為之前配置過熱過載功能 , 所以修改了 index.js 之後會自動過載, 頁面重新整理說明過載完成, 這個時候再次修改 print.js 的輸出, 熱替換後再點選按鈕, 發現輸出的是修改後的程式碼:
實現了 HMR(模組熱替換功能), 這樣修改模組的程式碼就不用熱過載重新載入整個檔案了, 它只會更新修改的模組部分, 對於開發來說很方便
HMR 修改樣式表(CSS)
藉助於 style-loader 的幫助, CSS 的模組熱替換實際上是相當簡單的, 當更新 CSS 依賴模組時, 此 loader 在後臺使用 module.hot.accept 來修補(patch) < style> 標籤
安裝
npm install style-loader css-loader --save-dev
配置 webpack.config.js
相關 style-loader 配置教程可以看 https://blog.csdn.net/qq593249106/article/details/84894989
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpack = require('webpack'); //引入 webpack
module.exports = {
entry: {
app: './src/index.js'
// print: './src/print.js'
},
devtool: 'inline-source-map', // 不同選項適用於不同環境
devServer: {
contentBase: './dist', //將dist目錄下的檔案(index.html)作為可訪問檔案, 如果不寫這個引數則預設與webpack.cofig.js的同級目錄
port: 8080, //埠號設為8080, 預設也是8080,
hot: true
},
module: {
rules: [ //配置載入器, 用來處理原始檔, 可以把es6, jsx等轉換成js, sass, less等轉換成css
{
test: /\.css$/, //配置要處理的檔案格式,一般使用正則表示式匹配
use: ['style-loader', 'css-loader'] //使用的載入器名稱
}
]
},
plugins: [ //webpack 通過 plugins 實現各種功能, 比如 html-webpack-plugin 使用模版生成 html 檔案
new CleanWebpackPlugin(['dist']), //設定清除的目錄
new HtmlWebpackPlugin({
filename: 'index.html', //設定生成的HTML檔案的名稱, 支援指定子目錄,如:assets/admin.html
title: 'Form HtmlWebpackPlugin', //設定生成的HTML的title
}),
new webpack.HotModuleReplacementPlugin() //啟用 webpack 內建的 HMR外掛
],
output: {
filename: '[name].bundle.js', //根據入口檔案輸出不同出口檔案
path: path.resolve(__dirname, 'dist')
}
};
現在新建一個 style.css 在 src 資料夾下用來做本次測試:
|- /dist //用於放打包後文件的資料夾
|- app.bundle.js //出口檔案
|- print.bundle.js //出口檔案
|- index.html //模板檔案
|- /node_modules
|- /src //用於放原始檔的資料夾
|- index.js //入口檔案
|- print.js
|- style.css //樣式檔案
|- package.json
|- webpack.config.js //webpack配置檔案
style.css
body {
background-color: red;
}
別忘了在 index.js 引入 style.css:
index.js
import _ from 'lodash';
import printMe from './print.js';
import './style.css'
function component() {
var element = document.createElement('div');
var btn = document.createElement('button'); //新建一個button物件
element.innerHTML = _.join(['Hello', 'webpack'], ' '); //要用到lodash的語法
btn.innerHTML = 'Click me and check the console!';
btn.onclick = printMe; //button觸發的事件是引用的print.js暴露的事件
element.appendChild(btn); //把button物件插入div中
return element;
}
var element = component(); //改用一個element儲存一下
document.body.appendChild(element);
if (module.hot) { //告訴 webpack 接受熱替換的模組
module.hot.accept('./print.js', function() {
console.log('Accepting the updated printMe module!');
document.body.removeChild(element); //刪掉舊的element
element = component(); //獲得一個修改後的element
document.body.appendChild(element); //重新插入到網頁中
})
}
啟動伺服器
終端輸入 npm run dev, 開啟網頁:
style.css 檔案生效了, 現在修改一下在 style.css 中修改一下, 將顏色改為綠色:
style.css
body {
/*background-color: red;*/
background-color: green;
}
這時, 網頁沒有過載直接變成了綠色, 實現了 css 的 HMR(熱替換)