建置效能

本指南包含一些有用的提示,用於改善建置/編譯效能。


一般

無論您是在開發生產中執行建置指令碼,下列最佳實務應有所幫助。

保持最新

使用最新的 webpack 版本。我們持續在進行效能改善。建議使用的最新 webpack 版本為

latest webpack version

保持Node.js最新也能有助於效能。此外,保持您的套件管理員(例如 npmyarn)最新也能有所幫助。較新的版本會建立更有效率的模組樹,並提升解析速度。

載入器

將載入器套用至必要的最小模組數。不要像這樣

module.exports = {
  //...
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: 'babel-loader',
      },
    ],
  },
};

使用 include 欄位僅套用實際上需要轉換的載入器模組

const path = require('path');

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

Bootstrap

每個額外的載入器/外掛都有啟動時間。盡量使用越少的工具越好。

解析

以下步驟可以增加解析速度

  • resolve.modulesresolve.extensionsresolve.mainFilesresolve.descriptionFiles 中的項目數量減至最少,因為它們會增加檔案系統呼叫的數量。
  • 如果您不使用符號連結(例如 npm linkyarn link),請設定 resolve.symlinks: false
  • 如果您使用非特定於內容的自訂解析外掛,請設定 resolve.cacheWithContext: false

Dll

使用 DllPlugin 將較少變更的程式碼移至個別編譯中。這將改善應用程式的編譯速度,儘管它會增加建置程序的複雜性。

較小 = 較快

縮小編譯的總大小以提升建置效能。嘗試保持區塊小。

  • 使用較少/較小的函式庫。
  • 在多頁面應用程式中使用 SplitChunksPlugin
  • 在多頁面應用程式中以 async 模式使用 SplitChunksPlugin
  • 移除未使用的程式碼。
  • 僅編譯您目前正在開發的程式碼部分。

工作人員池

thread-loader 可用於將昂貴的載入器卸載到工作人員池。

持續快取

在 webpack 組態中使用 cache 選項。在 package.json 中的 "postinstall" 中清除快取目錄。

自訂外掛程式/載入程式

設定它們的個人資料,以避免在此處造成效能問題。

進度外掛程式

可以透過從 webpack 的組態中移除 ProgressPlugin 來縮短建置時間。請記住,ProgressPlugin 可能無法為快速建置提供太多價值,因此請務必善用它的優點。


開發

下列步驟在開發中特別有用。

增量建置

使用 webpack 的監控模式。不要使用其他工具來監控您的檔案並呼叫 webpack。內建的監控模式將追蹤時間戳記,並將此資訊傳遞給編譯以進行快取失效。

在某些設定中,監控會回到輪詢模式。如果監控大量檔案,這可能會造成大量的 CPU 負載。在這些情況下,您可以使用 watchOptions.poll 來增加輪詢間隔。

在記憶體中編譯

以下工具程式透過在記憶體中編譯並提供資源,而非寫入磁碟,來提升效能

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

stats.toJson 速度

Webpack 4 預設會透過其 stats.toJson() 輸出大量資料。除非在遞增步驟中需要,否則請避免擷取 stats 物件的部分。v3.1.3 之後的 webpack-dev-server 包含一個重要的效能修正,以將從 stats 物件中擷取的資料量最小化,以進行每個遞增建置步驟。

開發人員工具

請注意不同 devtool 設定之間的效能差異。

  • "eval" 具有最佳效能,但無法協助您進行轉譯的程式碼。
  • 如果您能接受略差的對應品質,則 cheap-source-map 變體的效能會更好。
  • 針對遞增建置,請使用 eval-source-map 變體。

避免特定於生產的工具程式

某些工具程式、外掛程式和載入器僅在建置生產時才有意義。例如,在開發期間,通常沒有必要使用 TerserPlugin 來縮小和混淆您的程式碼。這些工具通常應該在開發中排除

  • TerserPlugin
  • [fullhash]/[chunkhash]/[contenthash]
  • AggressiveSplittingPlugin
  • AggressiveMergingPlugin
  • ModuleConcatenationPlugin

最小進入區塊

Webpack 僅將更新的區塊發射到檔案系統。對於某些組態選項,(HMR、[name]/[chunkhash]/[contenthash]output.chunkFilename 中、[fullhash]) 除了變更的區塊之外,進入區塊也會失效。

確保進入區塊易於發射,方法是保持其大小。下列組態會為執行時期程式碼建立一個額外的區塊,因此很容易產生

module.exports = {
  // ...
  optimization: {
    runtimeChunk: true,
  },
};

避免額外的最佳化步驟

Webpack 執行額外的演算法工作,以最佳化輸出的大小和載入效能。這些最佳化對於較小的程式碼庫來說效能很好,但對於較大的程式碼庫來說可能會很昂貴

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

沒有路徑資訊的輸出

Webpack 有能力在輸出套件中產生路徑資訊。但是,這會對將數千個模組打包的專案造成垃圾回收壓力。在 options.output.pathinfo 設定中關閉此功能

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

Node.js 版本 8.9.10-9.11.1

在 Node.js 版本 8.9.10 - 9.11.1 中的 ES2015 MapSet 實作中,有一個 效能回歸。Webpack 大量使用這些資料結構,因此此回歸會影響編譯時間。

較早和較新的 Node.js 版本不受影響。

TypeScript 載入器

若要在使用 ts-loader 時改善建置時間,請使用 transpileOnly 載入器選項。此選項本身會關閉類型檢查。若要再次獲得類型檢查,請使用 ForkTsCheckerWebpackPlugin。這會透過將每個類型檢查移至個別程序,來加速 TypeScript 類型檢查和 ESLint 程式碼檢查。

module.exports = {
  // ...
  test: /\.tsx?$/,
  use: [
    {
      loader: 'ts-loader',
      options: {
        transpileOnly: true,
      },
    },
  ],
};

生產

以下步驟在生產中特別有用。

原始碼對應表

原始碼對應表真的非常耗資源。你真的需要它們嗎?


特定工具問題

以下工具有一些特定問題,可能會降低建置效能

Babel

  • 將預設值/外掛的數量減到最少

TypeScript

  • 使用 fork-ts-checker-webpack-plugin 在一個獨立的程序中進行類型檢查。
  • 設定載入器來略過類型檢查。
  • happyPackMode: true / transpileOnly: true 中使用 ts-loader

Sass

  • node-sass 有個錯誤,會封鎖 Node.js 執行緒池中的執行緒。當與 thread-loader 一起使用時,請設定 workerParallelJobs: 2

6 貢獻者

sokratbroadleybyzykmadhavarshneywizardofhogwartsanikethsaha