banner
他山之石

他山之石

Webpack之構建速度優化

本文是我在使用 Webpack4 過程中的一些總結,介紹一些優化 Webpack 構建速度的方法。

image

Webpack 是當前最流行的打包工具,當前的最新版本是 Webpack4+,性能有了很大的提升,本文是我在使用過程中的一些總結,主要是提高 Webpack 的構建性能。

保持版本更新#

使用最新的 webpack 版本。新版本一般會進行性能優化。

保持最新的 Node.js 版本也能夠提升性能。除此之外,保證你的包管理工具 (例如 npm 或者 yarn) 為最新也能提升性能。較新的版本能夠建立更高效的模塊依賴樹以及提高解析速度。

在 Loader 中使用 include 或者 exclude#

配置 loader 的時候,使用 include,可以更精確指定要處理的目錄,可以減少不必要的遍歷,從而減少性能損失。同樣,對於已經明確知道的,不需要處理的目錄,則應該予以排除,從而進一步提升性能。故而,合理的設置 include 和 exclude,將會極大地提升 Webpack 打包優化速度。

module.exports = {
  //...
  module: {
    rules: [
      {
        test: /\.js$/,
        include: path.resolve(__dirname, 'src'),
        loader: 'babel-loader'
      }
    ]
  }
};

提高解析速度#

以下幾步可以提高解析速度:

  • 盡量減少 resolve.modules, resolve.extensions, resolve.mainFiles, resolve.descriptionFiles 中類目的數量,因為他們會增加文件系統調用的次數。
  • 如果你不使用 symlinks ,可以設置 resolve.symlinks: false (例如 npm link 或者 yarn link).
  • 如果你使用自定義解析 plugins ,並且沒有指定 context 資訊,可以設置 resolve.cacheWithContext: false 。

module.noParse#

防止 webpack 解析那些任何與給定正則表達式相匹配的文件。忽略的文件中不應該含有 import, require, define 的調用,或任何其他導入機制。忽略大型的類庫 可以提高構建性能。

module.exports = {
  //...
  module: {
    noParse: /jquery|lodash/,

    // 從 webpack 3.0.0 開始
    noParse: function(content) {
      return /jquery|lodash/.test(content);
    }
  }
};

babel-loader#

babel-loader 構建很慢,不僅要使用 exclude、include,盡可能準確的指定要編譯內容的目錄,而且要充分利用緩存,進一步提升性能。babel-loader 提供了 cacheDirectory 特定選項(默認 false),當有設置時,指定的目錄將用來緩存 loader 的執行結果。之後的 webpack 構建,將會嘗試讀取緩存,來避免在每次執行時,可能產生的、高性能消耗的 Babel 重新編譯過程。

通過使用 cacheDirectory 選項,將 babel-loader 提速至少兩倍。 這會將轉譯的結果緩存到文件系統中。

babel 在每個文件都插入了輔助代碼,使代碼體積過大!
babel 對一些公共方法使用了非常小的輔助代碼,比如 _extend。 默認情況下會被添加到每一個需要它的文件中

你可以引入 babel runtime 作為一個獨立模塊,來避免重複引入。

下面的配置禁用了 babel 自動對每個文件的 runtime 注入,而是引入 babel-plugin-transform-runtime 並且使所有輔助代碼從這裡引用。

rules: [
  // 'transform-runtime' 插件告訴 babel 要引用 runtime 來代替注入。
  {
    test: /\.js$/,
    exclude: /(node_modules|bower_components)/,
    use: {
      loader: 'babel-loader',
      options: {
        presets: ['@babel/preset-env'],
        plugins: ['@babel/transform-runtime']
      }
    }
  }
]

Dlls#

使用 DllPlugin 將更改不頻繁的代碼進行單獨編譯。這將改善引用程序的編譯速度,即使它增加了構建過程的複雜性。

Happypack 多進程構建#

由於 Node.js 的單進程限制,所有的 loader 雖然以 async 的形式來並發調用,但是還是運行在單個 node 的進程,以及在同一個事件循環中,這就直接導致了些問題:當同時讀取多個 loader 文件資源時,比如 babel-loader 需要 transform 各種 jsx,es6 的資源文件。在這種 CPU 密集型的場景下,Node 的單進程模型就沒有優勢了,而 Happypack 就是為解決此類問題而生。

Happypack 的處理思路是:將原有的 webpack 對 loader 的執行過程,從單一進程的形式擴展多進程模式,從而加速代碼構建;原本的流程保持不變,這樣可以在不修改原有配置的基礎上,來完成對編譯過程的優化,具體配置如下:

// webpack.config.js
const HappyPack = require('happypack');
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });

exports.module = {
  rules: [
    {
      test: /.js$/,
      include: [resolve('src')],
      exclude: /node_modules/,
      loader: 'happypack/loader?id=happybabel'
    }
  ]
};

exports.plugins = [
  new HappyPack({
    id: 'happybabel',
    loaders: ['babel-loader'],
    threadPool: happyThreadPool,
    cache: true,
    verbose: true
  })
];

Happypack 在編譯過程中,除了利用多進程的模式加速編譯,還同時開啟了 cache 計算,能充分利用緩存讀取構建文件,對構建的速度提升也是非常明顯的

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。