webpack系列文章:
- 【Webpack 性能優化系列(9) - 多程序打包】極大的提升項目打包建構速度!!!
- 【Webpack 性能優化系列(8) - PWA】使用漸進式網絡應用程式為我們的項目添加離線體驗
- 【Webpack 性能優化系列(7) - 懶加載和預加載】
- 【Webpack 性能優化系列(6) - code splitting 】通過代碼分割來擷取更小的 bundle,優化資源加載
- 【Webpack 性能優化系列(5) - tree shaking 】去除未引用代碼,減少代碼體積!!!
- 【Webpack 性能優化系列(4) - 緩存 】詳解如何做bable緩存和檔案資源緩存
- 【Webpack 性能優化系列(3) - oneOf】
- 【Webpack 性能優化系列(2) - source-map】
- 【Webpack 生産環境配置】近兩萬字長文總結學習如何提取css為單獨檔案、css的壓縮和相容性處理,如何壓縮html和js、如何做js文法檢查eslint和js相容性處理babel!!!
- 【Webpack 開發環境配置】萬字長文總結學習如何打包樣式資源、html資源、圖檔資源和其他資源?devServer是什麼,如何配置?
- 【Webpack 簡介及五個核心概念】
webpack性能優化
webpack性能優化主要指兩個環境:
- 開發環境性能優化
- 生産環境性能優化
除了前面的開發環境和生産環境配置,還有以下性能優化處理:
開發環境性能優化包括:
- 優化打包建構速度
- HMR
- 優化代碼調試
- source-map
生産環境性能優化包括:
- 優化打包建構速度
- oneOf
- babel緩存
- 多程序打包
- externals
- dll
- 優化代碼運作的性能
- 緩存(hash-chunkhash-contenthash)
- tree shaking
- code split
- 懶加載/預加載
- pwa
HMR 熱子產品替換
為什麼要使用
HMR 熱子產品替換
功能?
我們回看一下前面總結的開發環境配置:
/*
開發環境配置:能讓代碼運作
運作項目指令:
webpack 打包運作項目
npx webpack-dev-server 啟動webpack-dev-server
*/
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
{
// 處理less資源
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
// 處理css資源
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
// 處理圖檔資源
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
// 關閉es6子產品化
esModule: false,
outputPath: 'imgs'
}
},
{
// 處理html中img資源
test: /\.html$/,
loader: 'html-loader'
},
{
// 處理其他資源
exclude: /\.(html|js|css|less|jpg|png|gif)/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
outputPath: 'media'
}
}
]
},
plugins: [
// plugins的配置
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development',
devServer: {
contentBase: resolve(__dirname, 'build'),
compress: true,
port: 3000,
open: true
}
};
下面我們看一下這種配置存在什麼問題
運作指令:
npx webpack-dev-server
,啟動webpack-dev-server
然後在
index.js
檔案中列印一段話:
console.log('index.js檔案被加載了~');
隻要index.js檔案重新被加載,就會列印上面那段話
現在去修改樣式檔案
#box {
width: 400px;// 200px修改為400px
height: 200px;
background-image: url('../imgs/angular.jpg');
background-repeat: no-repeat;
background-size: 100% 100%;
}
修改之後,很明顯整體頁面被重新整理,内容被重新列印了一次
意思就是:當我們修改css檔案時,明明js檔案沒有變化,但js檔案也被重新加載了一次,是以打包的時候,看似隻修改了css檔案,實際上是把js檔案也重新打包了一次,這是一個問題。
再寫一個子產品:
在index.js中引入上面那個print子產品,并且在下面調用一下:
效果:
發現子產品被加載,并且子產品的print方法被調用執行了
現在我們修改一下print.js檔案,
'hello print'
改為`‘hello webpack’
console.log('print.js被加載了~');
function print() {
const content = 'hello webpack';
console.log(content);
}
export default print;
儲存檢視效果,可以發現整個頁面被重新重新整理了,所有代碼重新執行:
這個意思就代表:假設以後我們有100個js子產品,100個樣式子產品,如果隻修改其中某一個子產品,這整200個子產品就需要重新打包,這個速度可以想想是非常慢的,更不要說以後的子產品會越來越多,那打包情況隻會越來越慢。
是以我們想實作這樣的功能:如果隻有一個子產品發生變化,那麼隻需要修改這一個子產品代碼就足夠了,其他子產品理應是不變的
做這個功能要使用webpack的
HMR 熱子產品替換
HMR:
hot module replacement
熱子產品替換 / 子產品熱替換
作用:一個子產品發生變化,隻會重新打包這一個子產品(而不是打包所有子產品),極大提升建構速度
HMR功能的使用非常簡單,隻需要在devServer裡配置
hot:true
即可:
devServer: {
contentBase: resolve(__dirname, 'build'),
compress: true,
port: 3000,
open: true,
// 開啟HMR功能
// 當修改了webpack配置,新配置要想生效,必須重新webpack服務
hot: true
}
修改配置後,運作指令:
npx webpack-dev-server
,重新啟動webpack-dev-server
開啟HMR功能跟之前更新有什麼差別?
首先列印結果這裡已經顯示HMR功能已經開啟:
下面修改樣式檔案,儲存,可以發現隻更新一個樣式檔案,js檔案并不會重新加載:
可以發現:樣式檔案可以使用HMR功能,之是以能使用是因為style-loader内部實作了~
這也是為什麼我們在開發環境要使用
style-loader
,生産環境要用
MiniCssExtractPlugin.loader
提取成單獨檔案,因為開發環境借助
style-loader
能讓性能更好,打包速度更快,但是上線的時候考慮性能優化,是以不能用
前面樣式檔案可以使用HMR功能,js檔案行不行呢?
修改
print.js
檔案,儲存,發現整個頁面被重新重新整理了一遍,這一點可以知道js檔案預設不能使用HMR功能
html檔案可以使用HMR功能嗎?
在html檔案中修改一段代碼:
儲存後發現當開啟HMR功能後,html檔案改動後并沒有任何變化:
html檔案: 預設不能使用HMR功能,同時會導緻問題:html檔案不能熱更新了~
通過修改
entey
入口,改成一個數組,把html檔案引入就可以解決上面的問題了:
修改配置後,打包運作項目
測試發現html檔案也是沒有HMR功能的,一旦html檔案發生變化,整體頁面就會重新重新整理
那麼html檔案需要HMR功能嗎?
html不像js檔案,一個項目裡會有很多個js子產品,而運作的html隻會有一個,一旦發生變化,就一定要變化,它隻需要變化一個檔案,既然一定要變化,那就沒辦法優化,是以html檔案不用做HMR功能
前面講到了js預設不能使用HMR功能,這并不代表js就不需要HMR功能,如何對js檔案使用HMR功能?
用法:
if (module.hot) {
// 一旦 module.hot 為true,說明開啟了HMR功能。 --> 讓HMR功能代碼生效
module.hot.accept('./print.js', function() {
// 方法會監聽 print.js 檔案的變化,一旦發生變化,其他子產品不會重新打包建構。
// 會執行後面的回調函數
print();
});
}
修改
print.js
,檢視效果
可以發現,
print.js
會重新更新,但
index.js
不會變,即
index.js
不會重新加載,樣式和結構也不會重新加載,這就是js檔案的HMR功能的使用
注意:HMR功能對js的處理,隻能處理非入口js檔案的其他檔案。
為什麼呢?
因為入口檔案會将其他檔案全部引入,一旦入口檔案變化,其他檔案重新引入,就會重新加載,這是沒辦法阻止的,是以入口檔案是做不了HMR功能的,隻能對入口檔案引入的一些依賴或者其他檔案做HMR功能。
比如修改入口檔案下面的列印代碼:
儲存,可以發現所有東西都要重新打包建構:
參考
- https://www.bilibili.com/video/BV1e7411j7T5?p=17&spm_id_from=pageDriver