一般項目在完成後,會通過webpack進行打包,利用webpack對前端項目性能優化是一個十分重要的環節
如何優化
通過webpack優化前端的手段有:
- JS代碼壓縮
- CSS代碼壓縮
- Html檔案代碼壓縮
- 檔案大小壓縮
- 圖檔壓縮
- Tree Shaking
- 代碼分離
- 内聯 chunk
JS代碼壓縮
terser是一個JavaScript的解釋、絞肉機、壓縮機的工具集,可以幫助我們壓縮、醜化我們的代碼,讓bundle更小
在production模式下,webpack 預設就是使用 TerserPlugin 來處理我們的代碼的。如果想要自定義配置它,配置方法如下:
const TerserPlugin = require('terser-webpack-plugin')
module.exports = {
...
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true // 電腦cpu核數-1
})
]
}
}
屬性介紹如下:
- extractComments:預設值為true,表示會将注釋抽取到一個單獨的檔案中,開發階段,我們可設定為 false ,不保留注釋
- parallel:使用多程序并發運作提高建構的速度,預設值是true,并發運作的預設數量: os.cpus().length - 1
- terserOptions:設定我們的terser相關的配置:compress:設定壓縮相關的選項,mangle:設定醜化相關的選項,可以直接設定為truemangle:設定醜化相關的選項,可以直接設定為truetoplevel:底層變量是否進行轉換keep_classnames:保留類的名稱keep_fnames:保留函數的名稱
CSS代碼壓縮
CSS壓縮通常是去除無用的空格等,因為很難去修改選擇器、屬性的名稱、值等
CSS的壓縮我們可以使用另外一個插件:css-minimizer-webpack-plugin
npm install css-minimizer-webpack-plugin -D
配置方法如下:
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
module.exports = {
// ...
optimization: {
minimize: true,
minimizer: [
new CssMinimizerPlugin({
parallel: true
})
]
}
}
Html檔案代碼壓縮
使用HtmlWebpackPlugin插件來生成HTML的模闆時候,通過配置屬性minify進行html優化
module.exports = {
...
plugin:[
new HtmlwebpackPlugin({
...
minify:{
minifyCSS:false, // 是否壓縮css
collapseWhitespace:false, // 是否折疊空格
removeComments:true // 是否移除注釋
}
})
]
}
設定了minify,實際會使用另一個插件html-minifier-terser
檔案大小壓縮
對檔案的大小進行壓縮,減少http傳輸過程中寬帶的損耗
npm install compression-webpack-plugin -D
new ComepressionPlugin({
test:/\.(css|js)$/, // 哪些檔案需要壓縮
threshold:500, // 設定檔案多大開始壓縮
minRatio:0.7, // 至少壓縮的比例
algorithm:"gzip", // 采用的壓縮算法
})
圖檔壓縮
一般來說在打包之後,一些圖檔檔案的大小是遠遠要比 js 或者 css 檔案要來的大,是以圖檔壓縮較為重要
配置方法如下:
module: {
rules: [
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name]_[hash].[ext]',
outputPath: 'images/',
}
},
{
loader: 'image-webpack-loader',
options: {
// 壓縮 jpeg 的配置
mozjpeg: {
progressive: true,
quality: 65
},
// 使用 imagemin**-optipng 壓縮 png,enable: false 為關閉
optipng: {
enabled: false,
},
// 使用 imagemin-pngquant 壓縮 png
pngquant: {
quality: '65-90',
speed: 4
},
// 壓縮 gif 的配置
gifsicle: {
interlaced: false,
},
// 開啟 webp,會把 jpg 和 png 圖檔壓縮為 webp 格式
webp: {
quality: 75
}
}
}
]
},
]
}
Tree Shaking
Tree Shaking 是一個術語,在計算機中表示消除死代碼,依賴于ES Module的靜态文法分析(不執行任何的代碼,可以明确知道子產品的依賴關系)
在webpack實作Trss shaking有兩種不同的方案:
- usedExports:通過标記某些函數是否被使用,之後通過Terser來進行優化的
- sideEffects:跳過整個子產品/檔案,直接檢視該檔案是否有副作用
兩種不同的配置方案, 有不同的效果
usedExports
配置方法也很簡單,隻需要将usedExports設為true
module.exports = {
...
optimization:{
usedExports
}
}
使用之後,沒被用上的代碼在webpack打包中會加入unused harmony export mul注釋,用來告知 Terser 在優化時,可以删除掉這段代碼
sideEffects
sideEffects用于告知webpack compiler哪些子產品時有副作用,配置方法是在package.json中設定sideEffects屬性
如果sideEffects設定為false,就是告知webpack可以安全的删除未用到的exports
如果有些檔案需要保留,可以設定為數組的形式
"sideEffecis":[ "./src/util/format.js", "*.css" // 所有的css檔案]
上述都是關于javascript的tree shaking,css同樣也能夠實作tree shaking
css tree shaking
css進行tree shaking優化可以安裝PurgeCss插件
npm install purgecss-plugin-webpack -D
const PurgeCssPlugin = require('purgecss-webpack-plugin')module.exports = { ... plugins:[ new PurgeCssPlugin({ path:glob.sync(`${path.resolve('./src')}/**/*`), {nodir:true}// src裡面的所有檔案 satelist:function(){ return { standard:["html"] } } }) ]}
- paths:表示要檢測哪些目錄下的内容需要被分析,配合使用glob
- 預設情況下,Purgecss會将我們的html标簽的樣式移除掉,如果我們希望保留,可以添加一個safelist的屬性
代碼分離
将代碼分離到不同的bundle中,之後我們可以按需加載,或者并行加載這些檔案
預設情況下,所有的JavaScript代碼(業務代碼、第三方依賴、暫時沒有用到的子產品)在首頁全部都加載,就會影響首頁的加載速度
代碼分離可以分出出更小的bundle,以及控制資源加載優先級,提供代碼的加載性能
這裡通過splitChunksPlugin來實作,該插件webpack已經預設安裝和內建,隻需要配置即可
預設配置中,chunks僅僅針對于異步(async)請求,我們可以設定為initial或者all
module.exports = { ... optimization:{ splitChunks:{ chunks:"all" } }}
splitChunks主要屬性有如下:
- Chunks,對同步代碼還是異步代碼進行處理
- minSize: 拆分包的大小, 至少為minSize,如何包的大小不超過minSize,這個包不會拆分
- maxSize: 将大于maxSize的包,拆分為不小于minSize的包
- minChunks:被引入的次數,預設是1
内聯chunk
可以通過InlineChunkHtmlPlugin插件将一些chunk的子產品内聯到html,如runtime的代碼(對子產品進行解析、加載、子產品資訊相關的代碼),代碼量并不大,但是必須加載的
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin')const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = { ... plugin:[ new InlineChunkHtmlPlugin(HtmlWebpackPlugin,[/runtime.+\.js/]}