webpack 最佳配置指北

前言

對於入門選手來說,webpack 配置項不少很重,如何快速配置一個可用於線上環境的 webpack 就是一件值得思考的事情。其實熟悉 webpack 以後會發現很簡單,基礎的配置能夠分爲如下幾個方面: entryoutputmoderesolvemoduleoptimizationpluginsource mapperformance 等,本文就來重點分析下這些部分。css

內附一張 webpack 零配置對比圖片,關注公衆號【前端瓶子君】回覆【webpack】免費獲取pdf文件。html

1、配置入口 entry

一、單入口和多入口

將源文件加入到 webpack 構建流程,能夠是單入口:前端

module.exports = {
  entry: `./index.js`,
}
複製代碼

構建包名稱 [name]mainnode

或多入口:react

module.exports = {
  entry: { 
    "index": `./index.js`,
  },
}
複製代碼

key:value 鍵值對的形式:jquery

  • key:構建包名稱,即 [name] ,在這裏爲 index
  • value:入口路徑

入口決定 webapck 從哪一個模塊開始生成依賴關係圖(構建包),每個入口文件都對應着一個依賴關係圖。webpack

2. 動態配置入口文件

動態打包全部子項目

當構建項目包含多個子項目時,每次增長一個子系統都須要將入口文件寫入 webpack 配置文件中,其實咱們讓webpack 動態獲取入口文件,例如:git

// 使用 glob 等工具使用若干通配符,運行時得到 entry 的條目
module.exports = {
  entry: glob.sync('./project/**/index.js').reduce((acc, path) => {
    const entry = path.replace('/index.js', '')
    acc[entry] = path
    return acc
  }, {}),
}
複製代碼

則會將全部匹配 ./project/**/index.js 的文件做爲入口文件進行打包,若是你想要增長一個子項目,僅僅須要在 project 建立一個子項目目錄,並建立一個 index.js 做爲入口文件便可。github

這種方式比較適合入口文件不集中且較多的場景。web

動態打包某一子項目

在構建多系統應用或組件庫時,咱們每次打包可能僅僅須要打包某一模塊,此時,能夠經過命令行的形式請求打印某一模塊,例如:

npm run build --project components
複製代碼

在打包的時候解析命令行參數:

// 解析命令行參數
const argv = require('minimist')(process.argv.slice(2))
// 項目
const project = argv['project'] || 'index'
複製代碼

而後配置入口:

module.exports = {
  entry: { 
    "index": `./${project}/index.js`,
  } 
}
複製代碼

至關於:

module.exports = {
  entry: { 
    "index": `./components/index.js`,
  } 
}
複製代碼

固然,你能夠傳入其它參數,也能夠應用於多個地方,例如 resolve.alias 中。

2、配置出口 output

用於告知 webpack 如何構建編譯後的文件,能夠自定義輸出文件的位置和名稱:

module.exports = {
  output: { 
    // path 必須爲絕對路徑
    // 輸出文件路徑
    path: path.resolve(__dirname, '../../dist/build'),
    // 包名稱
    filename: "[name].bundle.js",
    // 或使用函數返回名(不經常使用)
    // filename: (chunkData) => {
    // return chunkData.chunk.name === 'main' ? '[name].js': '[name]/[name].js';
    // },
    // 塊名,公共塊名(非入口)
    chunkFilename: '[name].[chunkhash].bundle.js',
    // 打包生成的 index.html 文件裏面引用資源的前綴
    // 也爲發佈到線上資源的 URL 前綴
    // 使用的是相對路徑,默認爲 ''
    publicPath: '/', 
  }
}
複製代碼

在 webpack4 開發模式下,會默認啓動 output.pathinfo ,它會輸出一些額外的註釋信息,對項目調試很是有用,尤爲是使用 eval devtool 時。

filename[name] 爲 entry 配置的 key,除此以外,還能夠是 [id] (內部塊 id )、 [hash][contenthash] 等。

1. 瀏覽器緩存與 hash 值

對於咱們開發的每個應用,瀏覽器都會對靜態資源進行緩存,若是咱們更新了靜態資源,而沒有更新靜態資源名稱(或路徑),瀏覽器就可能由於緩存的問題獲取不到更新的資源。在咱們使用 webpack 進行打包的時候,webpack 提供了 hash 的概念,因此咱們可使用 hash 來打包。

在定義包名稱(例如 chunkFilenamefilename),咱們通常會用到哈希值,不一樣的哈希值使用的場景不一樣:

hash

build-specific, 哈希值對應每一次構建( Compilation ),即每次編譯都不一樣,即便文件內容都沒有改變,而且全部的資源都共享這一個哈希值,此時,瀏覽器緩存就沒有用了,能夠用在開發環境,生產環境不適用。

chunkhash

chunk-specific, 哈希值對應於 webpack 每一個入口點,每一個入口都有本身的哈希值。若是在某一入口文件建立的關係依賴圖上存在文件內容發生了變化,那麼相應入口文件的 chunkhash 纔會發生變化,適用於生產環境

contenthash

content-specific,根據包內容計算出的哈希值,只要包內容不變,contenthash 就不變,適用於生產環境

webpack 也容許哈希的切片。若是你寫 [hash:8] ,那麼它會獲取哈希值的前 8 位。

注意:
  • 儘可能在生產環境使用哈希
  • 按需加載的塊不受 filename 影響,受 chunkFilename 影響
  • 使用 hash/chunkhash/contenthash 通常會配合 html-webpack-plugin (建立 html ,並捆綁相應的打包文件) 、clean-webpack-plugin (清除原有打包文件) 一塊兒使用。

2. 打包成庫

當使用 webapck 構建一個能夠被其它模塊引用的庫時:

module.exports = {
  output: { 
    // path 必須爲絕對路徑
    // 輸出文件路徑
    path: path.resolve(__dirname, '../../dist/build'),
    // 包名稱
    filename: "[name].bundle.js",
    // 塊名,公共塊名(非入口)
    chunkFilename: '[name].[chunkhash].bundle.js',
    // 打包生成的 index.html 文件裏面引用資源的前綴
    // 也爲發佈到線上資源的 URL 前綴
    // 使用的是相對路徑,默認爲 ''
    publicPath: '/', 
    // 一旦設置後該 bundle 將被處理爲 library
    library: 'webpackNumbers',
    // export 的 library 的規範,有支持 var, this, commonjs,commonjs2,amd,umd
    libraryTarget: 'umd',
  }
}
複製代碼

3、配置模式 mode(webpack4)

設置 mode ,可讓 webpack 自動調起相應的內置優化。

module.exports = {
  // 能夠是 none、development、production
  // 默認爲 production
  mode: 'production'
}
複製代碼

或在命令行裏配置:

"build:prod": "webpack --config config/webpack.prod.config.js --mode production"
複製代碼

在設置了 mode 以後,webpack4 會同步配置 process.env.NODE_ENVdevelopmentproduction

webpack4 最引人注目的主要是:

  • 減少編譯時間

    打包時間減少了超過 60%

  • 零配置

    咱們能夠在沒有任何配置文件的狀況下將 webpack 用於各類項目

webpack4 支持零配置使用,這裏的零配置就是指,mode 以及 entry (默認爲 src/index.js)均可以經過入口文件指定,而且 webpack4 針對對不一樣的 mode 內置相應的優化策略。

1. production

配置:

// webpack.prod.config.js
module.exports = {
  mode: 'production',
}
複製代碼

至關於默認內置了:

// webpack.prod.config.js
module.exports = {
  performance: {
    // 性能設置,文件打包過大時,會報警告
    hints: 'warning'
  },
  output: {
    // 打包時,在包中不包含所屬模塊的信息的註釋
    pathinfo: false
  },
  optimization: {
    // 不使用可讀的模塊標識符進行調試
    namedModules: false,
    // 不使用可讀的塊標識符進行調試
    namedChunks: false,
    // 設置 process.env.NODE_ENV 爲 production
    nodeEnv: 'production',
    // 標記塊是不是其它塊的子集
    // 控制加載塊的大小(加載較大塊時,不加載其子集)
    flagIncludedChunks: true,
    // 標記模塊的加載順序,使初始包更小
    occurrenceOrder: true,
    // 啓用反作用
    sideEffects: true,
    // 肯定每一個模塊的使用導出,
    // 不會爲未使用的導出生成導出
    // 最小化的消除死代碼
    // optimization.usedExports 收集的信息將被其餘優化或代碼生成所使用
    usedExports: true,
    // 查找模塊圖中能夠安全的鏈接到其它模塊的片斷
    concatenateModules: true,
    // SplitChunksPlugin 配置項
    splitChunks: {
      // 默認 webpack4 只會對按需加載的代碼作分割
      chunks: 'async',
      // 表示在壓縮前的最小模塊大小,默認值是30kb
      minSize: 30000,
      minRemainingSize: 0,
      // 旨在與HTTP/2和長期緩存一塊兒使用 
      // 它增長了請求數量以實現更好的緩存
      // 它還能夠用於減少文件大小,以加快重建速度。
      maxSize: 0,
      // 分割一個模塊以前必須共享的最小塊數
      minChunks: 1,
      // 按需加載時的最大並行請求數
      maxAsyncRequests: 6,
      // 入口的最大並行請求數
      maxInitialRequests: 4,
      // 界定符
      automaticNameDelimiter: '~',
      // 塊名最大字符數
      automaticNameMaxLength: 30,
      cacheGroups: { // 緩存組
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true
        }
      }
    },
    // 當打包時,遇到錯誤編譯,將不會把打包文件輸出
    // 確保 webpack 不會輸入任何錯誤的包
    noEmitOnErrors: true,
    checkWasmTypes: true,
    // 使用 optimization.minimizer || TerserPlugin 來最小化包
    minimize: true,
  },
  plugins: [
    // 使用 terser 來優化 JavaScript
    new TerserPlugin(/* ... */),
    // 定義環境變量
    new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
    // 預編譯全部模塊到一個閉包中,提高代碼在瀏覽器中的執行速度
    new webpack.optimize.ModuleConcatenationPlugin(),
    // 在編譯出現錯誤時,使用 NoEmitOnErrorsPlugin 來跳過輸出階段。
    // 這樣能夠確保輸出資源不會包含錯誤
    new webpack.NoEmitOnErrorsPlugin()
  ]
}
複製代碼

2. development

配置:

// webpack.dev.config.js
module.exports = {
  mode: 'development',
}
複製代碼

至關於默認內置了:

// webpack.dev.config.js
module.exports = {
  devtool: 'eval',
  cache: true,
  performance: {
    // 性能設置,文件打包過大時,不報錯和警告,只作提示
    hints: false
  },
  output: {
    // 打包時,在包中包含所屬模塊的信息的註釋
    pathinfo: true
  },
  optimization: {
    // 使用可讀的模塊標識符進行調試
    namedModules: true,
    // 使用可讀的塊標識符進行調試
    namedChunks: true,
    // 設置 process.env.NODE_ENV 爲 development
    nodeEnv: 'development',
    // 不標記塊是不是其它塊的子集
    flagIncludedChunks: false,
    // 不標記模塊的加載順序
    occurrenceOrder: false,
    // 不啓用反作用
    sideEffects: false,
    usedExports: false,
    concatenateModules: false,
    splitChunks: {
      hidePathInfo: false,
      minSize: 10000,
      maxAsyncRequests: Infinity,
      maxInitialRequests: Infinity,
    },
    // 當打包時,遇到錯誤編譯,仍把打包文件輸出
    noEmitOnErrors: false,
    checkWasmTypes: false,
    // 不使用 optimization.minimizer || TerserPlugin 來最小化包
    minimize: false,
    removeAvailableModules: false
  },
  plugins: [
    // 當啓用 HMR 時,使用該插件會顯示模塊的相對路徑
    // 建議用於開發環境
    new webpack.NamedModulesPlugin(),
    // webpack 內部維護了一個自增的 id,每一個 chunk 都有一個 id。
    // 因此當增長 entry 或者其餘類型 chunk 的時候,id 就會變化,
    // 致使內容沒有變化的 chunk 的 id 也發生了變化
    // NamedChunksPlugin 將內部 chunk id 映射成一個字符串標識符(模塊的相對路徑)
    // 這樣 chunk id 就穩定了下來
    new webpack.NamedChunksPlugin(),
    // 定義環境變量
    new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),
  ]
}
複製代碼

3. none

不進行任何默認優化選項。

配置:

// webpack.com.config.js
module.exports = {
  mode: 'none',
}
複製代碼

至關於默認內置了:

// webpack.com.config.js
module.exports = {
  performance: {
   // 性能設置,文件打包過大時,不報錯和警告,只作提示
   hints: false
  },
  optimization: {
    // 不標記塊是不是其它塊的子集
    flagIncludedChunks: false,
    // 不標記模塊的加載順序
    occurrenceOrder: false,
    // 不啓用反作用
    sideEffects: false,
    usedExports: false,
    concatenateModules: false,
    splitChunks: {
      hidePathInfo: false,
      minSize: 10000,
      maxAsyncRequests: Infinity,
      maxInitialRequests: Infinity,
    },
    // 當打包時,遇到錯誤編譯,仍把打包文件輸出
    noEmitOnErrors: false,
    checkWasmTypes: false,
    // 不使用 optimization.minimizer || TerserPlugin 來最小化包
    minimize: false,
  },
  plugins: []
}
複製代碼

4. production、 development、none 總結

注意:關注公衆號【前端瓶子君】回覆【webpack】免費獲取pdf原文件。

production 模式下給你更好的用戶體驗:

  • 較小的輸出包體積
  • 瀏覽器中更快的代碼執行速度
  • 忽略開發中的代碼
  • 不公開源代碼或文件路徑
  • 易於使用的輸出資產

development 模式會給予你最好的開發體驗:

  • 瀏覽器調試工具
  • 快速增量編譯可加快開發週期
  • 運行時提供有用的錯誤消息

儘管 webpack4 在盡力讓零配置作到更多,但仍然是有限度的,大多數狀況下仍是須要一個配置文件。咱們能夠在項目的初期使用零配置,在後期業務複雜的時候再配置。

5. 環境變量 process.env.NODE_ENV

第三方框架或庫,以及咱們的業務代碼,都會針對不一樣的環境配置,執行不一樣的邏輯代碼,例如:

咱們能夠經過如下方式定義環境變量:

方法一:webpack4 中 mode: 'production' 已經默認配置了 process.env.NODE_ENV = 'production' ,因此 webapck4 能夠不定義

儘管 webpack4 中定義 mode 會自動配置 process.env.NODE_ENV ,那麼咱們就不須要手動配置環境變量了嗎?

其實否則,mode 只能夠定義成 developmentproduction ,而在項目中,咱們不只僅只有開發或生產環境,不少狀況下須要配置不一樣的環境(例如測試環境),此時咱們就須要手動配置其它環境變量(例如測試環境,就須要定義 process.env.NODE_ENV'test' ),你能夠採起如下方式:

方法二:webpack.DefinePlugin

// webpack編譯過程當中設置全局變量process.env
new webpack.DefinePlugin({
  'process.env': require('../config/dev.env.js')
}
複製代碼

config/prod.env.js

module.exports ={
  // 或 '"production"' ,環境變量的值須要是一個由雙引號包裹的字符串
  NODE_ENV: JSON.stringify('production') 
}
複製代碼

方法三:webpack 命令時, NODE_ENV=development

在 window 中配置 NODE_ENV=production 可能會卡住,因此使用 cross-env:

cross-env NODE_ENV=production webpack --config webpack.config.prod.js
複製代碼

方法四:使用 new webpack.EnvironmentPlugin(['NODE_ENV'])

EnvironmentPlugin 是一個經過 webpack.DefinePlugin 來設置 process.env 環境變量的快捷方式。

new webpack.EnvironmentPlugin({
  NODE_ENV: 'production',
});
複製代碼

注意:上面實際上是給 NODE_ENV 設置一個默認值 'production' ,若是其它地方有定義 process.env.NODE_ENV ,則該默認值無效。

4、配置解析策略 resolve

自定義尋找依賴模塊時的策略(例如 import _ from 'lodash'):

module.exports = {
  resolve: {
    // 設置模塊導入規則,import/require時會直接在這些目錄找文件
    // 能夠指明存放第三方模塊的絕對路徑,以減小尋找,
    // 默認 node_modules
    modules: [path.resolve(`${project}/components`), 'node_modules'],
    // import導入時省略後綴
    // 注意:儘量的減小後綴嘗試的可能性
    extensions: ['.js', '.jsx', '.react.js', '.css', '.json'],
    // import導入時別名,減小耗時的遞歸解析操做
    alias: {
      '@components': path.resolve(`${project}/components`),
      '@style': path.resolve('asset/style'),
    },
    // 不少第三方庫會針對不一樣的環境提供幾份代碼
    // webpack 會根據 mainFields 的配置去決定優先採用那份代碼
    // 它會根據 webpack 配置中指定的 target 不一樣,默認值也會有所不一樣
    mainFields: ['browser', 'module', 'main'],
  },
}
複製代碼

5、配置解析和轉換文件的策略 module

決定如何處理項目中不一樣類型的模塊,一般是配置 module.rules 裏的 Loader:

module.exports = {
  module: {
    // 指明 webpack 不去解析某些內容,該方式有助於提高 webpack 的構建性能
    noParse: /jquery/,
    rules: [
      {
        // 這裏編譯 js、jsx
        // 注意:若是項目源碼中沒有 jsx 文件就不要寫 /\.jsx?$/,提高正則表達式性能
        test: /\.(js|jsx)$/,
        // 指定要用什麼 loader 及其相關 loader 配置
        use: {
          loader: "babel-loader",
          options: {
            // babel-loader 支持緩存轉換出的結果,經過 cacheDirectory 選項開啓
            // 使用 cacheDirectory 選項將 babel-loader 的速度提升2倍
      		cacheDirectory: true,
      		// Save disk space when time isn't as important
      		cacheCompression: true,
      		compact: true,     
          }
        },
        // 排除 node_modules 目錄下的文件
        // node_modules 目錄下的文件都是採用的 ES5 語法,不必再經過 Babel 去轉換
        exclude: /node_modules/
        // 也能夠配置 include:須要引入的文件
      }
    ]
  }
}
複製代碼

1. noParse

指明 webpack 不去解析某些內容,該方式有助於提高 webpack 的構建性能。

2. rules

常見的 loader 有:

  • babel-loader:解析 .js 和 .jsx 文件

    // 配置 .babelrc
    {
      "presets": [
        [
          "@babel/preset-env",
        ],
        "@babel/preset-react"
      ],
      "plugins": [
        [
          "@babel/plugin-proposal-class-properties",
          {
            "loose": true
          }
        ],
        [
          "@babel/plugin-transform-runtime",
          {
            "absoluteRuntime": false,
            "corejs": false,
            "helpers": true,
            "regenerator": true,
            "useESModules": false
          }
        ],
      ]
    }
    複製代碼
  • tsx-loader:處理 ts 文件

  • less-loader:處理 less 文件,並將其編譯爲 css

  • sass-loader:處理 sass、scss 文件,並將其編譯爲 css

  • postcss-loader

    // postcss.config.js
    module.exports = { // 解析CSS文件而且添加瀏覽器前綴到 CSS 內容裏
    	plugins: [require('autoprefixer')],
    };
    複製代碼
  • css-loader:處理 css 文件

  • style-loader:將 css 注入到 DOM

  • file-loader:將文件上的import / require 解析爲 url,並將該文件輸出到輸出目錄中

  • url-loader:用於將文件轉換成 base64 uri 的 webpack 加載程序

  • html-loader:將 HTML 導出爲字符串, 當編譯器要求時,將 HTML 最小化

更多 loaders 可查看 LOADERS

6、配置優化 optimization(webpack4)

webapck4 會根據你所選擇的 mode 進行優化,你能夠手動配置,它將會覆蓋自動優化,詳細配置請見 Optimization

主要涉及兩方面的優化:

  • 最小化包
  • 拆包

1. 最小化包

  • 使用 optimization.removeAvailableModules 刪除已可用模塊
  • 使用 optimization.removeEmptyChunks 刪除空模塊
  • 使用 optimization.occurrenceOrder 標記模塊的加載順序,使初始包更小
  • 使用 optimization.providedExportsoptimization.usedExportsconcatenateModulesoptimization.sideEffects 刪除死代碼
  • 使用 optimization.splitChunks 提取公共包
  • 使用 optimization.minimizer || TerserPlugin 來最小化包

2. 拆包

當包過大時,若是咱們更新一小部分的包內容,那麼整個包都須要從新加載,若是咱們把這個包拆分,那麼咱們僅僅須要從新加載發生內容變動的包,而不是全部包,有效的利用了緩存。

拆分 node_modules

不少狀況下,咱們不須要手動拆分包,可使用 optimization.splitChunks

const path = require('path');
module.exports = {
  entry: path.resolve(__dirname, 'src/index.js'),
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[contenthash].js',
  },
  optimization: {
    splitChunks: {
      // 對全部的包進行拆分
      chunks: 'all',
    },
  },
};
複製代碼

咱們沒必要制定拆包策略,chunks: all 會自動將 node_modules 中的全部內容放入一個名爲 vendors〜main.js 的文件中。

拆分業務代碼
module.exports = {
  entry: {
    main: path.resolve(__dirname, 'src/index.js'),
    ProductList: path.resolve(__dirname, 'src/ProductList/ProductList.js'),
    ProductPage: path.resolve(__dirname, 'src/ProductPage/ProductPage.js'),
    Icon: path.resolve(__dirname, 'src/Icon/Icon.js'),
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[contenthash:8].js',
  },
};
複製代碼

採用多入口的方式,當有業務代碼更新時,更新相應的包便可

拆分第三方庫
const path = require('path');
const webpack = require('webpack');

module.exports = {
  entry: path.resolve(__dirname, 'src/index.js'),
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[contenthash].js',
  },
  optimization: {
    runtimeChunk: 'single',
    splitChunks: {
      chunks: 'all',
      maxInitialRequests: Infinity,
      minSize: 0,
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name(module) {
            // 獲取第三方包名
            const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];

            // npm 軟件包名稱是 URL 安全的,可是某些服務器不喜歡@符號
            return `npm.${packageName.replace('@', '')}`;
          },
        },
      },
    },
  },
};
複製代碼

當第三方包更新時,僅更新相應的包便可。

注意,當包太多時,瀏覽器會發起更多的請求,而且當文件太小時,對代碼壓縮也有影響。

動態加載

如今咱們已經對包拆分的很完全了,但以上的拆分僅僅是對瀏覽器緩存方面的優化,減少首屏加載時間,實際上咱們也可使用按需加載的方式來進一步拆分,減少首屏加載時間:

import React, { useState, useEffect } from 'react';
import './index.scss'

function Main() {
  const [NeighborPage, setNeighborPage] = useState(null)

  useEffect(() => {
    import('../neighbor').then(({ default: component }) => {
      setNeighborPage(React.createElement(component))
    });
  }, [])

  return NeighborPage
    ? NeighborPage
    : <div>Loading...</div>;
}

export default Main
複製代碼

7、配置 plugin

配置 Plugin 去處理及優化其它的需求,

module.exports = {
  plugins: [
    // 優化 require
    new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /en|zh/),
    // 用於提高構建速度
    createHappyPlugin('happy-babel', [{
      loader: 'babel-loader',
      options: {
        presets: ['@babel/preset-env', "@babel/preset-react"],
        plugins: [
          ['@babel/plugin-proposal-class-properties', {
            loose: true
          }]
        ],
        // babel-loader 支持緩存轉換出的結果,經過 cacheDirectory 選項開啓
        cacheDirectory: true,
        // Save disk space when time isn't as important
        cacheCompression: true,
        compact: true,
      }
    }])
  ]
}
複製代碼

經常使用 plugins:

  • html-webpack-plugin:生成 html 文件,並將包添加到 html 中
  • webpack-parallel-uglify-plugin:壓縮 js(多進程並行處理壓縮)
  • happypack:多線程loader,用於提高構建速度
  • hard-source-webpack-plugin:爲模塊提供中間緩存步驟,顯著提升打包速度
  • webpack-merge:合併 webpack 配置
  • mini-css-extract-plugin:抽離 css
  • optimize-css-assets-webpack-plugin:壓縮 css
  • add-asset-html-webpack-plugin:將 JavaScript 或 CSS 資產添加到 html-webpack-plugin 生成的 HTML 中

更多插件可見:plugins

8、配置devtool:source map

配置 webpack 如何生成 Source Map,用來加強調試過程。不一樣的值會明顯影響到構建(build)和從新構建(rebuild)的速度:

生產環境:默認爲 null ,通常不設置( none )或 nosources-source-map

開發環境:默認爲 eval ,通常設置爲 evalcheap-eval-source-mapcheap-module-eval-source-map

策略爲:

  • 使用 cheap 模式能夠大幅提升 souremap 生成的效率。 沒有列信息(會映射到轉換後的代碼,而不是映射到原始代碼),一般咱們調試並不關心列信息,並且就算 source map 沒有列,有些瀏覽器引擎(例如 v8) 也會給出列信息。
  • **使用 eval 方式可大幅提升持續構建效率。**參考官方文檔提供的速度對比表格能夠看到 eval 模式的編譯速度很快。
  • 使用 module 可支持 babel 這種預編譯工具(在 webpack 裏作爲 loader 使用)。

若是默認的 webpack minimizer 已經被重定義(例如 terser-webpack-plugin ),你必須提供 sourceMap:true 選項來啓用 source map 支持。

更多可查看:devtool

9、配置性能 performance

當打包是出現超過特定文件限制的資產和入口點,performance 控制 webpack 如何通知:

module.exports = {
  // 配置如何顯示性能提示
  performance: {
    // 可選 warning、error、false
    // false:性能設置,文件打包過大時,不報錯和警告,只作提示
    // warning:顯示警告,建議用在開發環境
    // error:顯示錯誤,建議用在生產環境,防止部署太大的生產包,從而影響網頁性能
    hints: false
  }
}
複製代碼

10、配置其它

1. watch 與 watchOptions

watch

監視文件更新,並在文件更新時從新編譯:

module.export = {
  // 啓用監聽模式
  watch: true,
}
複製代碼

webpack-dev-serverwebpack-dev-middleware 中,默認啓用了監視模式。

或者咱們能夠在命令行裏啓動監聽( --watch ):

webpack --watch --config webpack.config.dev.js
複製代碼
watchOptions
module.export = {
  watch: true,
  // 自定義監視模式
  watchOptions: {
    // 排除監聽
    ignored: /node_modules/,
    // 監聽到變化發生後,延遲 300ms(默認) 再去執行動做,
    // 防止文件更新太快致使從新編譯頻率過高
    aggregateTimeout: 300,
    // 判斷文件是否發生變化是經過不停的去詢問系統指定文件有沒有變化實現的
    // 默認 1000ms 詢問一次
    poll: 1000
  }
}
複製代碼

2. externals

排除打包時的依賴項,不歸入打包範圍內,例如你項目中使用了 jquery ,而且你在 html 中引入了它,那麼在打包時就不須要再把它打包進去:

<script
  src="https://code.jquery.com/jquery-3.1.0.js"
  integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
  crossorigin="anonymous">
</script>
複製代碼

配置:

module.exports = {
  // 打包時排除 jquery 模塊
  externals: {
    jquery: 'jQuery'
  }
};
複製代碼

3.target

構建目標,用於爲 webpack 指定一個環境:

module.exports = {
  // 編譯爲類瀏覽器環境裏可用(默認)
  target: 'web'
};
複製代碼

4. cache

緩存生成的 webpack 模塊和塊以提升構建速度。在開發模式中,緩存設置爲 type: 'memory' ,在生產模式中禁用。cache: truecache: {type: 'memory'} 的別名。要禁用緩存傳遞 false

module.exports = {
  cache: false
}
複製代碼

在內存中,緩存僅在監視模式下有用,而且咱們假設你在開發中使用監視模式。 在不進行緩存的狀況下,內存佔用空間較小。

5. name

配置的名稱,用於加載多個配置:

module.exports = {
  name: 'admin-app'
};
複製代碼

11、總結

本文僅僅是列出一些經常使用的配置項,全部的配置文件架構可見:WebpackOptions.json,你也能夠進入 webpack 官網瞭解更多。

往期 webpack 系列

五種可視化方案分析 webpack 打包性能瓶頸

窺探原理:手寫一個 JavaScript 打包器

想看往期更過系列文章,點擊前往 github 博客主頁

參考:

webpack

The 100% correct way to split your chunks with Webpack

webpack 4: mode and optimization

12、走在最後

  1. ❤️玩得開心,不斷學習,並始終保持編碼。👨💻

  2. 若有任何問題或更獨特的看法,歡迎評論或直接聯繫瓶子君(公衆號回覆 123 便可)!👀👇

  3. 👇歡迎關注:前端瓶子君,每日更新!👇

相關文章
相關標籤/搜索