前端性能優化: 包體積壓縮 82-、打包速度提升 65-
作者:海闊_天空
https://juejin.cn/post/7186315052465520698
壓縮項目打包後的體積大小、提升打包速度,是前端性能優化中非常重要的環節,筆者結合工作中的實踐總結,梳理出一些 常規且有效
的性能優化建議
項目背景
技術棧:vue-cli3 + vue2 + webpack4 主要插件:elementUI + echarts + axios + momentjs
目標: 通過一系列的優化方案,對比打包體積和速度的前後變化,來驗證方案的有效性
項目初始體積與速度
- 初始體積
2.25M
vue 項目可以通過添加 --report 命令:"build": "vue-cli-service build --report"
,打包後 dist 目錄會生成 report.html 文件,用來分析各文件的大小
或者通過安裝 webpack-bundle-analyzer
插件來分析,步驟如下:
1)安裝
npm install webpack-bundle-analyzer -D
2)vue.config.js 中 引入
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
configureWebpack: {
plugins: [
new BundleAnalyzerPlugin()
]
}
}
3)npm run serve 運行後,在瀏覽器打開http://127.0.0.1:8888/
可以看到分析頁面
- 初始打包速度
25386ms
開始優化 ✈︎
1、externals 提取項目依賴
從上面的打包分析頁面中可以看到,chunk-vendors.js
體積爲 2.21M
,其中最大的幾個文件都是一些公共依賴包,那麼只要把這些依賴提取出來,就可以解決 chunk-vendors.js 過大的問題
可以使用 externals
來提取這些依賴包,告訴 webpack 這些依賴是外部環境提供的,在打包時可以忽略它們,就不會再打到 chunk-vendors.js 中
1)vue.config.js 中配置:
module.exports = {
configureWebpack: {
externals: {
vue: 'Vue',
'vue-router': 'VueRouter',
axios: 'axios',
echarts: 'echarts'
}
}
2)在 index.html 中使用 CDN 引入依賴
<body>
<script src="http://lib.baomitu.com/vue/2.6.14/vue.min.js"></script>
<script src="http://lib.baomitu.com/vue-router/3.5.1/vue-router.min.js"></script>
<script src="http://lib.baomitu.com/axios/1.2.1/axios.min.js"></script>
<script src="http://lib.baomitu.com/echarts/5.3.2/echarts.min.js"></script>
</body>
驗證 externals 的有效性:
重新打包,最新數據如下:
打包體積:1.12M
打包速度:18879ms
使用 externals 後,包體積壓縮 50%、打包速度提升 26%
2、組件庫的按需引入
爲什麼沒有使用 externals 的方式處理組件庫呢?
externals 缺點:直接在 html 內引入的,失去了按需引入的功能,只能引入組件庫完整的 js 和 css
組件庫按需引入的原理:最終只引入指定組件和對應的樣式
elementUI 需要藉助 **babel-plugin-component **插件實現,插件的作用如下:
如按需引入 Button 組件:
import { Button } from 'element-ui'
Vue.component(Button.name, Button)
編譯後的文件(自動引入 button.css):
import _Button from "element-ui/lib/button";
import _Button2 from "element-ui/lib/theme-chalk/button.css";
// base.css是公共的樣式
import "element-ui/lib/theme-chalk/base.css";
Vue.component(_Button.name, _Button);
通過該插件,最終只引入指定組件和樣式,來實現減少組件庫體積大小
1)安裝 babel-plugin-component
npm install babel-plugin-component -D
2)babel.config.js 中引入
module.exports = {
presets: ['@vue/app'],
plugins: [
[
'component',
{
libraryName: 'element-ui',
styleLibraryName: 'theme-chalk'
}
]
]
};
驗證組件庫按需引入的有效性:
重新打包,最新數據如下:
打包體積:648KB
打包速度:15135ms
組件庫按需引入後,包體積壓縮 72%、打包速度提升 40%
同時 chunk-vendors.css
的體積也有了明顯的減少,從206KB
降到了82KB
原始體積:
按需引入後:
3、減小三方依賴的體積
繼續分析打包文件,項目中使用了 momentjs,發現打包後有很多沒有用到的語言包
使用 moment-locales-webpack-plugin
插件,剔除掉無用的語言包
1)安裝
npm install moment-locales-webpack-plugin -D
2)vue.config.js 中引入
const MomentLocalesPlugin = require('moment-locales-webpack-plugin');
module.exports = {
configureWebpack: {
plugins: [
new MomentLocalesPlugin({localesToKeep: ['zh-cn']})
]
}
}
驗證插件的有效性:
重新打包,最新數據如下:
打包體積:407KB
打包速度:10505ms
減小三方依賴體積後,包體積壓縮 82%、打包速度提升 59%
4、HappyPack 多線程打包
由於運行在 Node.js 之上的 webpack 是單線程模型的,我們需要 webpack 能同一時間處理多個任務,發揮多核 CPU 電腦的威力
HappyPack
就能實現多線程打包,它把任務分解給多個子進程去併發的執行,子進程處理完後再把結果發送給主進程,來提升打包速度
1)安裝
npm install HappyPack -D
2)vue.config.js 中引入
const HappyPack = require('happypack');
const os = require('os');
// 開闢一個線程池,拿到系統CPU的核數,happypack 將編譯工作利用所有線程
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
module.exports = {
configureWebpack: {
plugins: [
new HappyPack({
id: 'happybabel',
loaders: ['babel-loader'],
threadPool: happyThreadPool
})
]
}
}
驗證 HappyPack 的有效性:
重新打包,最新數據如下:
打包速度:8949ms
使用 HappyPack 後,打包速度進一步提升了 65%
由於測試項目較小,打包時間縮短的不算太多。實測發現越是複雜的項目,HappyPack 對打包速度的提升越明顯
5、Gzip 壓縮
線上的項目,一般都會結合構建工具 webpack 插件或服務端配置 nginx,來實現 http 傳輸的 gzip 壓縮,目的就是把服務端響應文件的體積儘量減小,優化返回速度
html、js、css 資源,使用 gzip 後通常可以將體積壓縮 70% 以上
這裏介紹下使用 webpack 進行 gzip 壓縮的方式,使用 compression-webpack-plugin
插件
1)安裝
npm install compression-webpack-plugin -D
2)vue.config.js 中引入
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = {
configureWebpack: {
plugins: [
new CompressionPlugin({
test: /\.(js|css)(\?.*)?$/i, //需要壓縮的文件正則
threshold: 1024, //文件大小大於這個值時啓用壓縮
deleteOriginalAssets: false //壓縮後保留原文件
})
]
}
}
驗證插件的有效性:
重新打包,原來 407KB
的體積壓縮爲 108KB
6、DllPlugin 動態鏈接庫
DllPlugin
與 externals 的作用相似,都是將依賴抽離出去,節約打包時間。區別是 DllPlugin 是將依賴單獨打包,這樣以後每次只構建業務代碼,而 externals 是將依賴轉化爲 CDN 的方式引入
當公司沒有很好的 CDN 資源或不支持 CDN 時,就可以考慮使用 DllPlugin ,替換掉 externals
DllPlugin 配置流程大致分爲三步:
1)創建 dll.config.js 配置文件
import { DllPlugin } from "webpack";
export default {
// 需要抽離的依賴
entry: {
vendor: ["vue", "vue-router", "axios", "echarts"]
},
mode: "production",
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
chunks: "all",
name: "vendor",
test: /node_modules/
}
}
}
},
output: {
filename: "[name].dll.js", // 輸出路徑和文件名稱
library: "[name]", // 全局變量名稱:其他模塊會從此變量上獲取裏面模塊
path: AbsPath("dist/static") // 輸出目錄路徑
},
plugins: [
new DllPlugin({
name: "[name]", // 全局變量名稱:減小搜索範圍,與output.library結合使用
path: AbsPath("dist/static/[name]-manifest.json") // 輸出目錄路徑
})
]
};
2)package.json 配置腳本
"build:dll": "webpack --config ./dll.config.js",
3)使用 DllReferencePlugin
將打包生成的 dll 文件,引用到需要的預編譯的依賴上來,並通過 html-webpack-tags-plugin
在打包時自動插入 dll 文件
vue.config.js 配置如下
import { DllReferencePlugin } from "webpack";
import HtmlTagsPlugin from "html-webpack-tags-plugin";
export default {
configureWebpack: {
plugins: [
new DllReferencePlugin({
manifest: AbsPath("dist/static/vendor-manifest.json") // manifest文件路徑
}),
new HtmlTagsPlugin({
append: false, // 在生成資源後插入
publicPath: "/", // 使用公共路徑
tags: ["static/vendor.dll.js"] // 資源路徑
})
]
}
};
先運行 npm run build:dll
打包生成依賴文件,以後只用運行 npm run build
構建業務代碼即可
優化總結
經過上面的一系列優化,可以看到:
-
包體積由原來的
2.25M
減少到407KB
,壓縮了 82% -
打包速度由原來的
25386ms
減少到8949ms
,提升了 65%
這些方式雖然很常規,但確實可以有效地提升項目的性能
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/zvLEabmoQ4cmwiVmbKD_0g