基于 Webpack 的應用包體尺寸優化

buddhistwwx 9年前發布 | 25K 次閱讀 前端技術 webpack

最近我在構建一個基于 React 的單頁應用,當我用 Google TestMySite 來檢測自己的站點時,它的反饋是加載時間過長,因此我開始考慮如何優化初次下載的包體大小。優化應用包體的第一步就是檢視當前的包體組成,判斷其中哪些依賴時必須的,我們在 Webpack 的回顯中可以看到當前的包體大小:

$ webpack -p --progress
Hash: dbce3735c9520e2dc682
Version: webpack 1.14.0
Time: 54264ms
            Asset     Size  Chunks             Chunk Names
    dist/index.js  3.29 MB       0  [emitted]  main
dist/index.js.map  13.7 MB       0  [emitted]  main
   [0] multi main 40 bytes {0} [built]
    + 1374 hidden modules

分析包體依賴

這里我們使用 webpack-bundle-analyzer 來分析 Webpack 生成的包體組成并且以可視化的方式反饋給開發者。我們可以使用npm來安裝該插件:

$ npm install --save-dev webpack-bundle-analyzer

然后我們需要修改webpack.config.js來引入該插件:

var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
// ...
plugins: [new BundleAnalyzerPlugin()]
// ...

然后我們照常使用 Webpack 編譯之后,可視化的結果會被展示在 http:// localhost:8888/ ,你大概可以看到如下的交互界面:

這個交互插件應該能幫你分析哪些依賴占據了主要的包體大小,這也提醒我們在引入某個功能的時候,應該只引入需要的模塊,以 Lodash 為例:

//1. Import the entire lodash library and add it to the bundle
import lodash from 'lodash'
lodash.groupBy(rows, 'id')

//2. Import only the required function from lodash
import groupBy from 'lodash/groupBy'
groupBy(rows, 'id')

設置合適的 Node 環境變量

設置合適的環境變量能夠幫助 Webpack 更好地去壓縮處理依賴中的代碼,我們需要在生產環境中將NODE_ENV設置為production:

plugins: [...
    new webpack.DefinePlugin({
             'process.env.NODE_ENV': '"production"'
    }),
..]

使用最小化的 SourceMap

當我們在生產環境下組合壓縮 JavaScript 文件時,Webpack 會為我們生成某個 SourceMap 文件來映射源文件的內容。在開發環境中我們經常會將devtool設置為eval,這樣會將大量的代碼信息打包到輸出包體中從而提升編譯速度。而開發環境中我們可以將該項設置為eval-source-map或者cheap-module-source-map,我們比較切換前后的包體大小可以發現縮小了將近 1MB 的內容:

$ webpack -p --progress
Hash: 68a52fddbcc2898a5899
Version: webpack 1.14.0
Time: 29757ms
            Asset     Size  Chunks             Chunk Names
    dist/index.js  1.71 MB       0  [emitted]  main
dist/index.js.map  464 bytes       0  [emitted]  main
   [0] multi main 40 bytes {0} [built]
    + 1365 hidden modules

其他常用插件

這里我列舉幾個常用的能夠用于減少包體大小的插件,我們可以根據項目需求選擇性的使用:

  • compression-webpack-plugin :該插件能夠將資源文件壓縮為.gz文件,并且根據客戶端的需求按需加載。

  • dedupeplugin :抽取出輸出包體中的相同或者近似的文件或者代碼,可能對于 Entry Chunk 有所負擔,不過能有效地減少包體大小。

  • uglifyjsplugin :壓縮輸出塊的大小,可以參考官方文檔。

  • ignoreplugin :用于忽略引入模塊中并不需要的內容,譬如當我們引入moment.js時,我們并不需要引入該庫中所有的區域設置,因此可以利用該插件忽略不必要的代碼。

...
var CompressionPlugin = require("compression-webpack-plugin");
...
let config = {
  entry: path.join(__dirname, '../app/index'),
  cache: false,
  devtool: 'cheap-module-source-map',
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': '"production"'
    }),
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.UglifyJsPlugin({
      mangle: true,
      compress: {
        warnings: false, // Suppress uglification warnings
        pure_getters: true,
        unsafe: true,
        unsafe_comps: true,
        screw_ie8: true
      },
      output: {
        comments: false,
      },
      exclude: [/\.min\.js$/gi] // skip pre-minified libs
    }),
    new webpack.IgnorePlugin(/^\.\/locale$/, [/moment$/]),
    new webpack.NoErrorsPlugin(),
    new CompressionPlugin({
      asset: "[path].gz[query]",
      algorithm: "gzip",
      test: /\.js$|\.css$|\.html$/,
      threshold: 10240,
      minRatio: 0
    })
    ...
  ],

引入該插件后包體的體積會受到進一步的壓縮:

$ webpack -p --progress
Hash: 68a52fddbcc2898a5899
Version: webpack 1.14.0
Time: 29757ms
            Asset     Size  Chunks             Chunk Names
    dist/index.js  1.54 MB       0  [emitted]  main
dist/index.js.gz   390 KB        0  [emitted]  main
dist/index.js.map  464 bytes     0  [emitted]  main   
   [0] multi main 40 bytes {0} [built]
    + 1365 hidden modules

 

來自:https://zhuanlan.zhihu.com/p/24928279

 

 本文由用戶 buddhistwwx 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!