天天看點

前端性能優化這樣做!包體積壓縮82%、打包速度提升65%

前端性能優化這樣做!包體積壓縮82%、打包速度提升65%
前端性能優化這樣做!包體積壓縮82%、打包速度提升65%

壓縮項目打包後的體積大小、提升打包速度,是前端性能優化中非常重要的環節,筆者結合工作中的實踐總結,梳理出一些 正常且有效 的性能優化建議

前端性能優化這樣做!包體積壓縮82%、打包速度提升65%

項目背景

技術棧: vue-cli3 + vue2 + webpack4

主要插件:elementUI + echarts + axios + momentjs

目标: 通過一系列的優化方案,對比打包體積和速度的前後變化,來驗證方案的有效性

項目初始體積與速度

  • 初始體積 2.25M
前端性能優化這樣做!包體積壓縮82%、打包速度提升65%

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
前端性能優化這樣做!包體積壓縮82%、打包速度提升65%

開始優化 ✈︎

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

前端性能優化這樣做!包體積壓縮82%、打包速度提升65%

打包速度:18879ms

前端性能優化這樣做!包體積壓縮82%、打包速度提升65%

使用 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

前端性能優化這樣做!包體積壓縮82%、打包速度提升65%

打包速度:15135ms

前端性能優化這樣做!包體積壓縮82%、打包速度提升65%

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

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

原始體積:

前端性能優化這樣做!包體積壓縮82%、打包速度提升65%

按需引入後:

前端性能優化這樣做!包體積壓縮82%、打包速度提升65%

3、減小三方依賴的體積

繼續分析打封包件,項目中使用了 momentjs,發現打包後有很多沒有用到的語言包

前端性能優化這樣做!包體積壓縮82%、打包速度提升65%

使用 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

前端性能優化這樣做!包體積壓縮82%、打包速度提升65%

打包速度:10505ms

前端性能優化這樣做!包體積壓縮82%、打包速度提升65%

減小三方依賴體積後,包體積壓縮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

前端性能優化這樣做!包體積壓縮82%、打包速度提升65%

使用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

前端性能優化這樣做!包體積壓縮82%、打包速度提升65%

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%

這些方式雖然很正常,但确實可以有效地提升項目的性能

#頭條創作挑戰賽#

繼續閱讀