獲取全套webpack 4.x教程,請訪問瓦力博客
本小節(jié)主要給大家介紹如何提高代碼的性能?我們從打包工具入手,然后到預提模塊(Preloading),預加載模塊(Prefetching)。
1.打包分析
- 官方提供的分析工具{:target="_blank"}
- webpack-chart{:target="_blank"}:webpack stats 可交互餅圖
- webpack-visualizer{:target="_blank"} :可視化并分析你的 bundle,檢查哪些模塊占用空間,哪些可能是重復使用的
- webpack-bundle-analyzer{:target="_blank"} :一個 plugin 和 CLI 工具,它將 bundle 內容展示為便捷的、交互式、可縮放的樹狀圖形式
- webpack bundle optimize helper{:target="_blank"} :此工具會分析你的 bundle,并為你提供可操作的改進措施建議,以減少 bundle 體積大小。
打包分析是指當webpack對我們的代碼打包過后,我們使用分析工具對打包后的文件進行一定的分析,幫助我們看打包后的代碼有沒有繼續(xù)提升的空間。
生成stats.json
您可以通過運行webpack --profile --json> stats.json為此工具生成所需的JSON文件
package.json
{
"scripts": {
"dev": "npx webpack-dev-server --config webpack.config.js --mode=development --colors",
"prod": "npx webpack --config webpack.config.js --mode=production",
"build": "npx webpack --config webpack.config.js --mode=development --colors"
+ "analyse": "npx webpack --profile --json> stats.json --config webpack.config.js --mode=development --colors"
},
}
運行webpack
yarn run analyse

在我們的項目下面生成了一個stats.json文件,將stats.json文件上傳到官方分析工具中就可以了。
2.使用webpackBundleAnalyzer
安裝webpack-bundle-analyzer
yarn add -D webpack-bundle-analyzer
webpack.config.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin()
]
}

3.prefetch
- Preloading官方{:target="_blank"}
在聲明import時,使用下面這些內置指令,可以讓webpack輸出resource hint(資源提示)來告知瀏覽器:
- prefetch(預獲取): 將來某些導航下可能需要的資源
- preload(預加載):當前導航下可能需要資源
上面我是看中文的文檔,有英文能力的小伙伴可以看英文,這樣理解比較準確。小菜本想在這里說說個人理解,但是寫出來后,感覺語言描述的不是很清楚,那還是用代碼來演示吧。
splitChunks: {
chunks: 'all'
}
webpack官方默認chunks:async,官方為什么要默認chunks:async呢?當我們在引入loadsh,jquery庫時,如果配置chunks: 'all',那么肯定會幫助我們把loadsh、jquery單獨拆分開來,但是這樣做并不能提升首頁的代碼性能,原因是在瀏覽器第一次加載時,還是需要我們加載loadsh、jquery庫,只有當我們的代碼第二次加載時,瀏覽器才會從緩存中去找,提高我們第二次頁面加載訪問速度。webpack是想讓我們第一次加載時,訪問速度就是最快。舉個列子
未優(yōu)化的代碼
src/index.js
document.addEventListener('click',()=>{
const element = document.createElement('div');
let sum = 0;
for(let i=1;i<=100;i++){
sum +=i;
}
sum = 0;
for(let i=1;i<=100;i++){
sum +=i;
}
sum = 0;
for(let i=1;i<=100;i++){
sum +=i;
}
sum = 0;
for(let i=1;i<=100;i++){
sum +=i;
}
sum = 0;
for(let i=1;i<=100;i++){
sum +=i;
}
sum = 0;
for(let i=1;i<=100;i++){
sum +=i;
}
sum = 0;
for(let i=1;i<=100;i++){
sum +=i;
}
sum = 0;
for(let i=1;i<=100;i++){
sum +=i;
}
element.innerHTML = `0~100的和為${sum}`;
document.body.appendChild(element)
})
編譯webpack
yarn run build
打開dist/index.html,找到coverage?;蛘呖旖莘绞?code>Ctrl + Shift + P,輸入coverage

打開后刷新頁面,然后點擊index.js

可以看到index.js未使用利用率27.9%,我們可以優(yōu)化一下index.js代碼
優(yōu)化后
新建src/util/click.js
function handleClick(){
const element = document.createElement('div');
let sum = 0;
for(let i=1;i<=100;i++){
sum +=i;
}
sum = 0;
for(let i=1;i<=100;i++){
sum +=i;
}
sum = 0;
for(let i=1;i<=100;i++){
sum +=i;
}
sum = 0;
for(let i=1;i<=100;i++){
sum +=i;
}
sum = 0;
for(let i=1;i<=100;i++){
sum +=i;
}
sum = 0;
for(let i=1;i<=100;i++){
sum +=i;
}
sum = 0;
for(let i=1;i<=100;i++){
sum +=i;
}
sum = 0;
for(let i=1;i<=100;i++){
sum +=i;
}
element.innerHTML = `0~100的和為${sum}`;
document.body.appendChild(element)
}
export default handleClick
src/index.js
document.addEventListener('click',()=>{
import('./util/click').then(({default:func}) =>{
func();
})
})
運行webpack
yarn run build

從上面的截圖可以了解到,index.js未使用率降低到了24.3%,小菜這里有個疑惑就是mian.js的未使用率上升了,按道理應該是要下降的。小菜也只能在這里猜測下,雖然index.js里面的代碼被移到click.js里面,估計demo寫的太簡單,代碼太少,webpack打包后,mian.js的代碼代碼量增加了,從而導致未使用的代碼率上升。如果后面有機會的話,小菜會專門寫一小節(jié)分析下,感興趣的小伙伴也可以自己研究下,然后在評論區(qū)留言分享也行。

webpack打包后,會有一個1.js文件被分割出來(大家如果想改名字,請查看上一節(jié))那么就會帶來一個問題,比如在首頁上有一個登陸按鈕,首頁加載好后,用戶點擊登陸,然后才會加載登陸程序,這樣會不會影響用戶體驗,如果按照上面那種方式確實會有這個問題。我們希望當主程序加載完成后再去加載子程序,還是上面那個例子,當首頁加載完成后,在瀏覽器空閑的時候去加載登陸程序,這樣一來就解決上面那個問題。
4.使用prefetch優(yōu)化
繼上面demo我們做點小修改
src/index.js
document.addEventListener('click',()=>{
import(/* webpackPrefetch: true */'./util/click').then(({default:func}) =>{
func();
})
})
運行webpack
yarn run build

打開瀏覽器的控制臺,刷新頁面,可以看到0.js文件被加載了。大家可以把魔法注釋去掉,在刷新瀏覽器看看。
5.使用preload優(yōu)化
src/index.js
document.addEventListener('click',()=>{
import(/* webpackPreload: true */'./util/click').then(({default:func}) =>{
func();
})
})

打開瀏覽器的控制臺,刷新頁面,可以看到0.js文件也被加載了。
6.prefetch和preload區(qū)別
不正確地使用 webpackPreload 會有損性能,請謹慎使用
preload和 prefetch 指令相比,preload 指令有許多不同之處:
- preload chunk 會在父 chunk 加載時,以并行方式開始加載。prefetch chunk 會在父 chunk 加載結束后開始加載
- preload chunk 具有中等優(yōu)先級,并立即下載。prefetch chunk 在瀏覽器閑置時下載
- preload chunk 會在父 chunk 中立即請求,用于當下時刻。prefetch chunk 會用于未來的某個時刻
- 瀏覽器支持程度不同
7.總結
webpack官方在配置中chunks: 'async'寫的是異步,是想讓我們編寫異步程序來提高代碼的性能,緩存能夠帶來的代碼提升非常有限,我們后面寫代碼程序應該重點關注代碼利用率,提高代碼利用率才是真正提高代碼性能,如果頁面代碼暫時不用,就采用異步懶加載的形勢,主代碼加載完成后利用空閑時間來加載其他子代碼。