Webpack構建性能優化指南

本指南翻譯自webpack官方性能指南文檔:https://webpack.js.org/guides/build-performance/

構建性能

本指南涵蓋了對增進構建或編譯性能的一些有效的提示。


General

以下提示對開發環境或者生產環境都有效。

Stay Up to Date

保持最新的webpack版本。我們總是在改進webpack的性能。目前最新的webpack版本爲:v4.41.4
使用最新的Node.js也可以提升性能。同樣的,保持npm或者yarn這樣的包管理器的版本也同樣可以提升性能。新版本擁有更高效的模塊樹與更快的解析速度。

Loaders

對需要的模塊採用對應Loader,例如:

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

以上示例通過include屬性圈定了babel-loader的作用範圍,如果不使用該屬性,則babel-loader將會對所有的js文件作業。

Bootstrap

每一個額外的Loader或者插件都會消耗一定的啓動時間,嘗試使用儘可能少的工具。

Resolving

以下幾點可以提升解析速度:

  • 降低resolve.modules、resolve.extensions、resolve.mainFiles、resolve.descriptionFiles這些選項中item的數量,因爲它們會導致更頻繁的IO。
  • 如果不使用symlinks(例如npm link或yarn link),那麼將resolve.symlinks設爲false。
  • 如果使用了自定義的插件,則將resolve.cacheWithContext設置爲false。

Dlls

使用DllPlugin插件將不常變更的代碼進行單獨編譯。儘管這會增加構建的複雜度,但會提高應用的編譯速度。

Smaller = Faster

降低被編譯文件的體積同樣可以提升構建性能。想辦法使chunk更小。

  • 使用體積更小/熟練更少的庫。
  • 在多頁應用中使用SplitChunksPlugin插件。
  • 在多頁應用中的async模式下使用SplitChunksPlugin插件。
  • 移除未被使用的代碼。
  • 只編譯當前你正在開發的代碼。

Worker Pool

thread-loader可將開銷昂貴的loader轉移至線程池執行。不過不能使用太多的線程,這對node.js運行時來說引發過載。另外也要降低線程與主進程模塊之間的信息傳輸,因爲IPC是昂貴的。

Persistent cache

通過cache-loader開啓持續緩存的能力。

Custom plugins/loaders

對於自定義的插件與loader,請自行分析優化性能。

Progress plugin

移除ProgressPlugin可能會縮短少許的構建時間。但是要記住,這並不會帶來可觀的構建速度優化,所以在移除該插件之前要平衡好取捨。

Development

以下優化手段在開發環境是尤其有效的。

Incremental Builds

使用webpack的watch模式,別使用其它工具來監聽文件的變化再來調用webpack。webpack內建的watch模式會保留時間戳的信息並將該信息給到編譯器以使緩存失效。

在一些設置中,監聽是靠輪詢來完成的。隨着監聽文件數量的增多,這會增加大量CPU的計算量。在這種情況下,可以通過watchOptions.poll來增加輪詢間隔。

Compile in Memory

以下工具通過內存編譯以及內存伺服的方式提升了性能,可以嘗試使用:

  • webpack-dev-server
  • webpack-hot-middleware
  • webpack-dev-middleware

stats.toJson speed

webpack4默認情況下會通過stats.toJson()輸出大量數據。除非在增量步驟中是必須的,否則避免檢索stats對象。webpack-dev-server在v3.1.3之後的版本針對於這一問題做了大量的性能方面的優化。

Devtool

不同的devtool設置所引起的性能是不同的,要有這個意識。

  • "eval"擁有最好的性能,不過它不會保留源代碼。
  • "cheap-source-map"帶來的性能損耗還可以,它會有一些性能損耗。
  • "eval-source-map"用來增量構建。
    在大多數情況下,cheap-module-eval-source-map是最適中的方案。

Avoid Production Specific Tooling

確保工具、插件、loader只是用於生產環境而不是開發環境,否則會帶來不需要的資源開銷。例如,在開發環境下通常不需要對代碼做混淆與壓縮,比如使用TerserPlugin來實現這個能力,開發環境下是不需要的。下面這些工具在開發環境下一般都是需要被摘出來的:

  • TerserPlugin
  • ExtractTextPlugin
  • [hash]/[chunkhash]
  • AggressiveSplittingPlugin
  • ModuleConcatenationPlugin

Minimal Entry Chunk

WebPack僅向文件系統發送更新的chunks。對於一些配置選項,(例如:HMR,[name]/[chunkhash]inOutput.chunkfilename,[hash])除更改的chunks外,入口chunk是無效的。

使入口chunk保持小的體量才能使更新的成本更低。下面的代碼塊會抽取一個包含僅僅是在運行時包含其它子塊的chunk:

new CommonsChunkPlugin({
  name: 'manifest',
  minChunks: Infinity,
});

Avoid Extra Optimization Steps

webpack會進行額外的邏輯運算工作來優化輸出代碼的體量與加載性能。下面優化選項對於小型的項目代碼來說是有效的,不過對於大型項目來說那就不太適用了:

module.exports = {
  // ...
  optimization: {
    removeAvailableModules: false,
    removeEmptyChunks: false,
    splitChunks: false,
  },
};

Output Without Path Info

webpack有能力在輸出的Bundle中攜帶路徑信息。然而,在有上千個組件的項目中會導致垃圾收集器的壓力。可使用以下選項將這個功能關閉:

module.exports = {
  // ...
  output: {
    pathinfo: false,
  },
};

Node.js Versions 8.9.10-9.11.1

在Node.js 8.9.10 ~ 9.11.1的版本區間內,Map和Set的實現在性能方面表現很差,所以這影響到了webpack的編譯時間。在這之前與之後的版本都沒有受到影響,所以要避免使用這個版本內的Node.js。

#Production
以下優化選項尤其適用於生產環境

Multiple Compilations

當使用多重編譯時,下面這些工具可能會幫到你:

  • parallel-webpack 可以在線程池中完成編譯。
  • cache-loader 緩存可在多次編譯中共享。

Source Maps

SourceMap是非常昂貴的,你真的需要它嗎?

一些工具的問題

下面這些工具含有一些問題,這些問題會導致性能上有一些影響:

Babel

  • 降低preset/plugin的數量。

TypeScript

  • 在單獨的進程中使用fork-ts-checker-webpack-plugin用於類型檢查。
  • 配置loader跳過類型檢查。
  • 在happyPackMode: true或transpileOnly: true中使用ts-loader。

Sass

  • node-sass有一個Bug,這個bug會阻斷Node.js線程池中的線程。當通過thread-loader使用它時,請將workerParallelJobs設置爲2。
發佈了73 篇原創文章 · 獲贊 146 · 訪問量 65萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章