世界熱門:前端性能優(yōu)化,壓縮包體積、提升打包速度

2023-01-12 17:21:49 來源:51CTO博客

項(xiàng)目背景

壓縮項(xiàng)目打包后的體積大小、提升打包速度,是前端性能優(yōu)化中非常重要的環(huán)節(jié),筆者結(jié)合工作中的實(shí)踐總結(jié),梳理出一些 ?常規(guī)且有效?? 的性能優(yōu)化建議


(資料圖片)

技術(shù)棧: vue-cli3 + vue2 + webpack4主要插件:elementUI + echarts + axios + momentjs

目標(biāo):通過一系列的優(yōu)化方案,對比打包體積和速度的前后變化,來驗(yàn)證方案的有效性

項(xiàng)目初始體積與速度

初始體積 ??2.25M??

vue 項(xiàng)目可以通過添加--report命令: ??"build": "vue-cli-service build --report"??,打包后 dist 目錄會生成 report.html 文件,用來分析各文件的大小

或者通過安裝 ??webpack-bundle-analyzer?? 插件來分析,步驟如下:

1)安裝

npm install webpack-bundle-analyzer -D復(fù)制代碼

2)vue.config.js中 引入

const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;module.exports = {  configureWebpack: {      plugins: [         new BundleAnalyzerPlugin()      ]  }}復(fù)制代碼

3)npm run serve運(yùn)行后,在瀏覽器打開??http://127.0.0.1:8888/?? 可以看到分析頁面

初始打包速度 ??25386ms??

開始優(yōu)化 ??

1、externals 提取項(xiàng)目依賴

從上面的打包分析頁面中可以看到,??chunk-vendors.js?? 體積為 ??2.21M??,其中最大的幾個(gè)文件都是一些公共依賴包,那么只要把這些依賴提取出來,就可以解決 chunk-vendors.js 過大的問題

可以使用 ??externals?? 來提取這些依賴包,告訴 webpack 這些依賴是外部環(huán)境提供的,在打包時(shí)可以忽略它們,就不會再打到 chunk-vendors.js 中

1)vue.config.js 中配置:

module.exports = {  configureWebpack: {    externals: {      vue: "Vue",      "vue-router": "VueRouter",      axios: "axios",      echarts: "echarts"    }}復(fù)制代碼

2)在 index.html 中使用 CDN 引入依賴

    <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>  復(fù)制代碼

驗(yàn)證 externals 的有效性:

重新打包,最新數(shù)據(jù)如下:

打包體積:??1.12M??

打包速度:??18879ms??

使用 externals 后,包體積壓縮50%、打包速度提升26%

2、組件庫的按需引入

為什么沒有使用 externals 的方式處理組件庫呢?

externals缺點(diǎn):直接在html內(nèi)引入的,失去了按需引入的功能,只能引入組件庫完整的js和css

組件庫按需引入的原理:最終只引入指定組件和對應(yīng)的樣式

elementUI 需要借助 ??babel-plugin-component?? 插件實(shí)現(xiàn),插件的作用如下:

如按需引入 Button 組件:

import { Button } from "element-ui"Vue.component(Button.name, Button)復(fù)制代碼

編譯后的文件(自動引入 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);復(fù)制代碼

通過該插件,最終只引入指定組件和樣式,來實(shí)現(xiàn)減少組件庫體積大小

1)安裝 babel-plugin-component

npm install babel-plugin-component -D復(fù)制代碼

2)babel.config.js中引入

module.exports = {  presets: ["@vue/app"],  plugins: [    [      "component",      {        libraryName: "element-ui",        styleLibraryName: "theme-chalk"      }    ]  ]};復(fù)制代碼

驗(yàn)證組件庫按需引入的有效性:

重新打包,最新數(shù)據(jù)如下:

打包體積:??648KB??

打包速度:??15135ms??

組件庫按需引入后,包體積壓縮72%、打包速度提升40%

同時(shí) ??chunk-vendors.css?? 的體積也有了明顯的減少,從??206KB??降到了??82KB??

原始體積:

按需引入后:

3、減小三方依賴的體積

繼續(xù)分析打包文件,項(xiàng)目中使用了 momentjs,發(fā)現(xiàn)打包后有很多沒有用到的語言包

使用 ??moment-locales-webpack-plugin?? 插件,剔除掉無用的語言包

1)安裝

npm install moment-locales-webpack-plugin -D復(fù)制代碼

2)vue.config.js 中引入

const MomentLocalesPlugin = require("moment-locales-webpack-plugin");module.exports = {  configureWebpack: {     plugins: [       new MomentLocalesPlugin({localesToKeep: ["zh-cn"]})     ]  }}復(fù)制代碼

驗(yàn)證插件的有效性:

重新打包,最新數(shù)據(jù)如下:

打包體積:??407KB??

打包速度:??10505ms??

減小三方依賴體積后,包體積壓縮82%、打包速度提升59%

4、HappyPack 多線程打包

由于運(yùn)行在 Node.js 之上的 webpack 是單線程模型的,我們需要 webpack 能同一時(shí)間處理多個(gè)任務(wù),發(fā)揮多核 CPU 電腦的威力

??HappyPack?? 就能實(shí)現(xiàn)多線程打包,它把任務(wù)分解給多個(gè)子進(jìn)程去并發(fā)的執(zhí)行,子進(jìn)程處理完后再把結(jié)果發(fā)送給主進(jìn)程,來提升打包速度

1)安裝

npm install HappyPack -D復(fù)制代碼

2)vue.config.js 中引入

const HappyPack = require("happypack");const os = require("os");// 開辟一個(gè)線程池,拿到系統(tǒng)CPU的核數(shù),happypack 將編譯工作利用所有線程const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });module.exports = {  configureWebpack: {     plugins: [       new HappyPack({        id: "happybabel",        loaders: ["babel-loader"],        threadPool: happyThreadPool      })     ]  }}復(fù)制代碼

驗(yàn)證 HappyPack 的有效性:

重新打包,最新數(shù)據(jù)如下:

打包速度:??8949ms??

使用HappyPack后,打包速度進(jìn)一步提升了65%

由于測試項(xiàng)目較小,打包時(shí)間縮短的不算太多。實(shí)測發(fā)現(xiàn)越是復(fù)雜的項(xiàng)目,HappyPack 對打包速度的提升越明顯

5、Gzip壓縮

線上的項(xiàng)目,一般都會結(jié)合構(gòu)建工具 webpack 插件或服務(wù)端配置 nginx,來實(shí)現(xiàn) http 傳輸?shù)?gzip 壓縮,目的就是把服務(wù)端響應(yīng)文件的體積盡量減小,優(yōu)化返回速度

html、js、css資源,使用 gzip 后通常可以將體積壓縮70%以上

這里介紹下使用 webpack 進(jìn)行 gzip 壓縮的方式,使用 ??compression-webpack-plugin?? 插件

1)安裝

npm install compression-webpack-plugin -D復(fù)制代碼

2)vue.config.js 中引入

const CompressionPlugin = require("compression-webpack-plugin");module.exports = {  configureWebpack: {     plugins: [      new CompressionPlugin({        test: /\.(js|css)(\?.*)?$/i, //需要壓縮的文件正則        threshold: 1024, //文件大小大于這個(gè)值時(shí)啟用壓縮        deleteOriginalAssets: false //壓縮后保留原文件      })     ]  }}復(fù)制代碼

驗(yàn)證插件的有效性:

重新打包,原來 ??407KB?? 的體積壓縮為 ??108KB??

6、DllPlugin 動態(tài)鏈接庫

??DllPlugin?? 與 externals 的作用相似,都是將依賴抽離出去,節(jié)約打包時(shí)間。區(qū)別是 DllPlugin 是將依賴單獨(dú)打包,這樣以后每次只構(gòu)建業(yè)務(wù)代碼,而 externals 是將依賴轉(zhuǎn)化為 CDN 的方式引入

當(dāng)公司沒有很好的 CDN 資源或不支持 CDN 時(shí),就可以考慮使用 DllPlugin ,替換掉 externals

DllPlugin 配置流程大致分為三步:

1)創(chuàng)建 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結(jié)合使用            path: AbsPath("dist/static/[name]-manifest.json") // 輸出目錄路徑        })    ]};復(fù)制代碼

2)package.json 配置腳本

"build:dll": "webpack --config ./dll.config.js",復(fù)制代碼

3)使用 ??DllReferencePlugin?? 將打包生成的dll文件,引用到需要的預(yù)編譯的依賴上來,并通過 ??html-webpack-tags-plugin?? 在打包時(shí)自動插入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"] // 資源路徑      })    ]  }};復(fù)制代碼

先運(yùn)行 ??npm run build:dll?? 打包生成依賴文件,以后只用運(yùn)行 ??npm run build?? 構(gòu)建業(yè)務(wù)代碼即可

優(yōu)化總結(jié)

經(jīng)過上面的一系列優(yōu)化,可以看到:

包體積由原來的 2.25M減少到 407KB,壓縮了82%打包速度由原來的 25386ms減少到 8949ms,提升了65%

這些方式雖然很常規(guī),但確實(shí)可以有效地提升項(xiàng)目的性能

完整項(xiàng)目:??點(diǎn)此下載??

標(biāo)簽: 最新數(shù)據(jù) 速度提升 全局變量

上一篇:世界快看:【深入淺出Seata原理及實(shí)戰(zhàn)】「入門基礎(chǔ)專題」帶你透析認(rèn)識Seata分布式事務(wù)服務(wù)的原理和流程(1)
下一篇:當(dāng)前熱文:如何制作一個(gè)羊了個(gè)羊游戲4:道具的實(shí)現(xiàn)