webpack筆記-生產環境與開發環境常用plugin介紹(五)


mode 和 plugin

前邊我們介紹 mode 時提過,mode 不同值會影響 webpack 構建配置,其中有一個就是會啟用 DefinePlugin 來設置process.env.NODE_ENV 的值,方便代碼中判斷構建環境。

除此之外,development production兩個不同的 mode 之間還有其他 plugin 使用上的區別,這里詳細介紹一下:

development

development 下會啟用 NamedChunksPlugin 和 NamedModulesPlugin,這兩個 plugin 官方文檔並沒有詳細的介紹,主要作用是在 Hot Module Replacement(熱模塊替換,后續簡稱 HMR)開啟時,模塊變化時的提示內容顯示 chunk 或者 module 名稱,而不是 ID。

production

production 下會啟動多個 plugins,分別是:

  • FlagDependencyUsagePlugin 在構建時給使用的依賴添加標識,用於減少構建生成的代碼量。
  • FlagIncludedChunksPlugin 在構建時給 chunk 中所包含的所有 chunk 添加 id,用於減少不必要的 chunk。
  • ModuleConcatenationPlugin 構建時添加作用域提升的處理,用於減少構建生成的代碼量,詳細參考:module-concatenation-plugin
  • NoEmitOnErrorsPlugin 編譯時出錯的代碼不生成,避免構建出來的代碼異常。
  • OccurrenceOrderPlugin 按使用的次數來對模塊進行排序,可以進一步減少構建代碼量。
  • SideEffectsFlagPlugin 在構建時給帶有 Side Effects 的代碼模塊添加標識,用於優化代碼量時使用。
  • TerserPlugin 壓縮 JS 代碼,參考:Terser

production mode 下啟用的大量 plugin都是為了優化生成代碼而使用的,和配置的 optimization 的內容息息相關,詳細可以查閱:optimization

下面介紹下其中用到的一些plugin的使用,幫我們理解plugin。

DefinePlugin

DefinePlugin 是 webpack 內置的插件,可以使用webpack.DefinePlugin 直接獲取。

在不同的 mode 中,會使用 DefinePlugin 來設置運行時的 process.env.NODE_ENV 常量。DefinePlugin 用於創建一些在編譯時可以配置值,在運行時可以使用的常量,如下例子:

module.exports = {
  // ...
  plugins: [
    new webpack.DefinePlugin({
      PRODUCTION: JSON.stringify(true), // const PRODUCTION = true
      VERSION: JSON.stringify('5fa3b9'), // const VERSION = '5fa3b9'
      BROWSER_SUPPORTS_HTML5: true, // const BROWSER_SUPPORTS_HTML5 = 'true'
      TWO: '1+1', // const TWO = 1 + 1,
      CONSTANTS: {
        APP_VERSION: JSON.stringify('1.1.2') // const CONSTANTS = { APP_VERSION: '1.1.2' }
      }
    }),
  ],
}

有了上面的配置,就可以在應用代碼文件中,訪問配置好的常量了,如:

console.log("Running App version " + VERSION);

if(!BROWSER_SUPPORTS_HTML5) require("html5shiv");

對上面配置簡單解釋下:

  • 如果配置的值是字符串,那么整個字符串會被當成代碼片段來執行,其結果作為最終變量的值,如上面的"1+1",最后的結果是2
  • 如果配置的值不是字符串,也不是一個對象字面量,那么該值會被轉為一個字符串,如true,最后的結果是'true'
  • 如果配置的是一個對象字面量,那么該對象的所有 key 會以同樣的方式去定義

這樣我們就可以理解為什么要使用 JSON.stringify()了,因為 JSON.stringify(true)的結果是 'true'JSON.stringify("5fa3b9") 的結果是 "5fa3b9"

社區中關於 DefinePlugin 使用得最多的方式是定義環境常量,例如 PRODUCTION = true或者 __DEV__ = true

建議使用 process.env.NODE_ENV: ...的方式來定義 process.env.NODE_ENV,而不是使用 process: { env: { NODE_ENV: ... } } 的方式,因為這樣會覆蓋掉process這個對象,可能會對其他代碼造成影響。

TerserPlugin

webpack mode 為 production 時會啟用 TerserPlugin 來壓縮 JS 代碼,我們看一下如何使用的:

module.exports = {
  // ...
  // TerserPlugin 的使用比較特別,需要配置在 optimization 字段中,屬於構建代碼優化的一部分
  optimization: {
    minimize: true, // 啟用代碼壓縮
    minimizer: [new TerserPlugin({
      test: /\.js(\?.*)?$/i, // 只處理 .js 文件
      cache: true, // 啟用緩存,可以加速壓縮處理
    })], // 配置代碼壓縮工具
  },
}

關於 TerserPlugin 的更多配置參考官方文檔:terser-webpack-plugin

在以前的版本 webpack 是使用 UglifyWebpackPlugin來壓縮 JS 代碼,后邊更換為 TerserPlugin了,可以更好地處理新的 JS 代碼語法。

IgnorePlugin

IgnorePlugin DefinePlugin一樣,也是一個webpack內置的插件,可以直接使用 webpack.IgnorePlugin來獲取。

這個插件用於忽略某些特定的模塊,讓webpack不把這些指定的模塊打包進去。例如我們使用 moment.js,直接引用后,里邊有大量的 i18n 的代碼,導致最后打包出來的文件比較大,而實際場景並不需要這些 i18n 的代碼,這時我們可以使用 IgnorePlugin 來忽略掉這些代碼文件,配置如下:

module.exports = {
  // ...
  plugins: [
    new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
  ]
}

IgnorePlugin 配置的參數有兩個,第一個是匹配引入模塊路徑的正則表達式,第二個是匹配模塊的對應上下文,即所在目錄名。

webpack-bundle-analyzer

這個 plugin 可以用於分析 webpack 構建打包的內容,用於查看各個模塊的依賴關系和各個模塊的代碼內容多少,便於開發者做性能優化。

webpack-bundle-analyzer是第三方的包,使用前需要安裝,配置上很簡單,僅僅引入 plugin 即可,在構建時可以在瀏覽器中查看分析結果:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  // ...
  plugins: [
    new BundleAnalyzerPlugin(),
  ],
}

使用這個可以配合 IgnorePlugin 來過濾掉部分大而無用的第三方模塊。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM