上篇:webpack筆記(一)
文章目錄
- 三、webpack的高級概念
- 1.Tree Shaking概念
- 如何配置?
- 2.Dev和Prod模式的區分打包
- 區分兩個環境運行
- 解決公共部分提取
- 3.Webpack和Code Splitting
- 配置
- 4.代碼分割SplitChunkPlugin引數配置詳解
- 魔法注釋
- 5.Lazy Loading 懶加載,chunk是什么
- 懶加載:通過import()來異步的加載一個模塊
- chunk
- 6.打包分析,Preloading,Prefetching
- 打包分析
- Preloading和Preloading
三、webpack的高級概念
1.Tree Shaking概念
前端中的tree-shaking可以理解為通過工具"搖"我們的JS檔案,將其中用不到的代碼"搖"掉,是一個性能優化的范疇,具體來說,在 webpack 專案中,有一個入口檔案,相當于一棵樹的主干,入口檔案有很多依賴的模塊,相當于樹枝,實際情況中,雖然依賴了某個模塊,但其實只使用其中的某些功能,通過 tree-shaking,將沒有使用的模塊搖掉,這樣來達到洗掉無用代碼的目的,
Tree Shaking 只支持ES Module
如何配置?
在開發環境
// webpack.config.js
optimization: {
usedExports: true
}
// package.json
"sideEffect": false,
// "sideEffect": ["*.css"] 不希望tree-shaking的配置在這里
在生產環境,自動配置好tree-shaking
2.Dev和Prod模式的區分打包
在開發環境和生成環境,有source-map,DevServer、HMR、壓縮等的區別,
區分兩個環境運行
package.json
{
"scripts": {
"dev": "webpack-dev-server --config webpack.dev.js",
"build": "webpack --config webpack.prod.js"
},
}
新建兩個檔案webpack.dev.js和webpack.prod.js
但是有很多相同的代碼!
解決公共部分提取
提取公共部分到webpack.common.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: {
main: './src/index.js'
},
output: {
publicPath: '/',
filename: '[name].js',
path: path.join(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
targets: {
edge: '17',
firefox: '60',
chrome: '67',
safari: '11.1'
}
}
]
]
}
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new CleanWebpackPlugin()
],
};
安裝 webpack-merge
npm install webpack-merge -D
改寫webpack.prod.js
const { merge } = require('webpack-merge');
const commonConfig = require('./webpack.common.js');
const prodConfig = {
mode: 'production'
};
module.exports = merge(commonConfig, prodConfig);
改寫webpack.dev.js
const webpack = require('webpack');
const { merge } = require('webpack-merge');
const commonConfig = require('./webpack.common.js');
const devConfig = {
mode: 'development',
devtool: 'source-map',
devServer: {
contentBase: './dist'
// hot: true,
// hotOnly: true
},
plugins: [new webpack.HotModuleReplacementPlugin()],
optimization: {
usedExports: true
}
};
module.exports = merge(commonConfig, devConfig);
3.Webpack和Code Splitting
代碼分割
在以前,為了減少 HTTP 請求,通常地,我們都會把所有的代碼都打包成一個單獨的 JS 檔案,但是,如果這個 JS 檔案體積很大的話,那就得不償失了,
這時,我們不妨把所有代碼分成一塊一塊,需要某塊代碼的時候再去加載它;還可以利用瀏覽器的快取,下次用到它的話,直接從快取中讀取,很顯然,這種做法可以加快我們網頁的加載速度,美滋滋!
所以說,Code Splitting 其實就是把代碼分成很多很多塊( chunk)咯,
配置
optimization: {
splitChunks: {
chunks: 'all'
}
}
然后會生成main.js和vendors~main.js
異步代碼
function getComponent() {
return import('lodash').then(({ default: _ }) => {
var element = document.createElement('div');
element.innerHTML = _.join(['Dell', 'Lee'], '-');
return element;
});
}
getComponent().then(element => {
document.body.appendChild(element);
});
代碼分割和webpack無關,webpack中實作代碼分割,兩種方式
1.同步代碼:只需要在webpack.common.js中做optimization的配置即可
2.異步代碼(import):異步代碼,無需做任何配置,會自動進行代碼分割
4.代碼分割SplitChunkPlugin引數配置詳解
SplitChunkPlugin配置
魔法注釋
return import(/* webpackChunkName: "lodash" */'lodash')
這樣會生成vendors~lodash.js這個檔案
打包生成檔案名和指定名稱相同
optimization: {
splitChunks: {
cacheGroups: {
vendors: false,
default: false
}
}
}
默認配置
module.exports = {
//...
optimization: {
splitChunks: {
// chunks:async只對異步代碼進行代碼分割,all會同步異步都分割
// 我們打包一個同步代碼塊,會尋找vendors配置,如果在node_modules中,會進行分割
chunks: 'async',
// 大于30kb,進行代碼分割
minSize: 30000,
maxSize: 0,
// 至少用幾次才會被分割
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
name: true,
// =>快取組
cacheGroups: {
// 不同的組
vendors: {
test: /[\\/]node_modules[\\/]/,
// 優先級
priority: -10
},
default: {
minChunks: 2,
priority: -20,
// 重用現有模塊
reuseExistingChunk: true
}
}
}
}
};
5.Lazy Loading 懶加載,chunk是什么
懶加載:通過import()來異步的加載一個模塊
import()回傳一個Promise型別
function getComponent() {
return import(/* webpackChunkName: "lodash-dj" */ 'lodash').then(
({ default: _ }) => {
var element = document.createElement('div');
element.innerHTML = _.join(['Dell', 'Lee'], '-');
return element;
}
);
}
document.addEventListener('click', () => {
getComponent().then(element => {
document.body.appendChild(element);
});
});
async await改寫
async function getComponent() {
const { default: _ } = await import(
/* webpackChunkName: "lodash-dj" */ 'lodash'
);
var element = document.createElement('div');
element.innerHTML = _.join(['Dell', 'Lee'], '-');
return element;
}
document.addEventListener('click', async () => {
const element = await getComponent();
document.body.appendChild(element);
})
chunk
打包只生成的每一個js檔案都稱為一個chunk
// 簡易配置代碼分割,交給webpack自動處理
optimization: {
splitChunks: {
chunks: 'all',
}
}
6.打包分析,Preloading,Prefetching
打包分析
github webpack/analyse
# 輸出打包資訊到 stats.json
webpack --profile --json > stats.json --config webpack.dev.js
webpack-bundle-analyzer工具使用
Install
npm install --save-dev webpack-bundle-analyzer
Usage (as a plugin)
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
plugins: [
new BundleAnalyzerPlugin()
]
打包完成之后自動打開127.0.0.1:8888查看分析
Preloading和Preloading
參考原文:聊一聊webpack中的preloading和prefetching
官方檔案:預取/預加載模塊(prefetch/preload module)
在瀏覽器中 按 Ctrl + Shift + P ,然后在彈出的對話框中輸入 coverage
從紅色的方框中可以看出當前加載的檔案中在當前頁面中的利用率
通過異步加載,提升代碼利用率,在加載當前頁的時候,異步加載不必要的代碼
現在我們就看出來 webopack 為什么要使用 chunks: 'async' 這樣的默認配置了,
webpack 優化的側重點是代碼的使用率而不是快取,只是使用快取的方式來優化意義是不大的,通過異步的方式提高代碼的利用率才能比較大程度地提高網站的性能,
有些小伙伴可能會想,能不能在加載完頁面網路空閑的時候先把這些檔案加載進來呀,真聰明,這就是接下來要講的 Preloading 和 Prefetching,
-
Prefetching
使用方法也比較簡單,就是在要異步加載的檔案前面加上
/* webpackPrefetch: true */這個 magic comment 即可,我們把需要互動才能用到的代碼,完全可以寫在異步組件里,
document.addEventListener('click', () => { import(/* webpackPrefetch: true */ './click.js').then(({default: func}) => { func(); }) });生成的 0.js 是 click.js 打包之后,可以看出在頁面加載完之后的空閑時間還沒有點擊頁面時已經加載了 0.js ,當點擊頁面時,0.js 直接從快取中讀取,因此耗時非常短,
-
Preloading 和 Prefetching 有什么區別?
兩者的最大區別在于,Prefetching 是在核心代碼加載完成之后帶寬空閑的時候再去加載,而 Preloading 是和核心代碼檔案一起去加載的,
因此,使用 Prefetching 的方式去加載異步檔案更合適一些,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/250238.html
標籤:其他
上一篇:性能優化之回流重繪
