nodejs交互工具庫 -- webpack-merge和webpack-chain

nodejs交互工具庫系列

做用
chalk-pipe 使用更簡單的樣式字符串建立粉筆樣式方案
chalk 正確處理終端字符串樣式
Commander.js 完整的 node.js 命令行解決方案
Inquirer.js 一組通用的交互式命令行用戶界面。
slash 系統路徑符處理
minimist 解析參數選項
dotenv 將環境變量從 .env文件加載到process.env中
dotenv-expand 擴展計算機上已經存在的環境變量
hash-sum 很是快的惟一哈希生成器
deepmerge 深度合併兩個或多個對象的可枚舉屬性。
yaml-front-matter 解析yaml或json
resolve 實現node的 require.resolve()算法,這樣就能夠異步和同步地使用require.resolve()表明文件
semver npm的語義版本器
leven 測量兩字符串之間的差別<br/>最快的JS實現之一
lru cache 刪除最近最少使用的項的緩存對象
portfinder 自動尋找 800065535內可用端口號
ora 優雅的終端轉輪
envinfo 生成故障排除軟件問題(如操做系統、二進制版本、瀏覽器、已安裝語言等)時所需的通用詳細信息的報告
memfs 內存文件系統與Node's fs API相同實現
execa 針對人類的流程執行
webpack-merge 用於鏈接數組和合並對象,從而建立一個新對象
webpack-chain 使用鏈式API去生成簡化webpack版本配置的修改
strip-ansi 從字符串中去掉ANSI轉義碼
address 獲取當前機器的IP, MAC和DNS服務器。
default-gateway 經過對OS路由接口的exec調用得到機器的默認網關
joi JavaScript最強大的模式描述語言和數據驗證器。
fs-extra 添加了未包含在原生fs模塊中的文件系統方法,並向fs方法添加了promise支持
Acorn 一個小而快速的JavaScript解析器,徹底用JavaScript編寫。
zlib.js ZLIB.js是ZLIB(RFC1950), DEFLATE(RFC1951), GZIP(RFC1952)和PKZIP在JavaScript實現。

nodejs交互工具庫 -- chalk-pipe和chalkcss

nodejs交互工具庫 -- commander和Inquirerhtml

nodejs交互工具庫 -- slash, minimist和dotenv, dotenv-expandvue

nodejs交互工具庫 -- hash-sum, deepmerge和yaml-front-matternode

nodejs交互工具庫 -- resolve和semverjquery

nodejs交互工具庫 -- leven, lru cache和portfinderwebpack

nodejs交互工具庫 -- ora和envinfogit

nodejs交互工具庫 -- memfs和execagithub

nodejs交互工具庫 -- webpack-merge和webpack-chainweb

nodejs交互工具庫 -- strip-ansi, address, default-gateway和joi算法

nodejs交互工具庫 -- fs-extra, Acorn和zlib

webpack-merge - Merge designed for Webpack

webpack-merge 提供 merge 函數用於鏈接數組和合並對象,從而建立一個新對象. 若是遇到函數,它將執行它們,經過算法運行結果,而後再次將返回值包裝到函數中.

這個行爲在配置webpack時特別有用,儘管它的用途不止於此. 不管什麼時候你須要合併配置對象,webpack-merge均可以派上用場.

merge(...configuration | [...configuration])

merge 是API的核心,也是最重要的思想。一般這就是您所須要的,除非您想要進一步定製

const { merge } = require('webpack-merge');

// Default API
const output = merge(object1, object2, object3, ...);

// 您能夠直接傳遞一個對象數組.
// 這適用於全部可用的功能.
const output = merge([object1, object2, object3]);

// 與右邊匹配的鍵優先:
const output = merge(
  { fruit: "apple", color: "red" },
  { fruit: "strawberries" }
);
console.log(output);
// { color: "red", fruit: "strawberries"}

Limitations

注意 Promises不被支持! 若是你想返回一個包裹配置的 Promise, merge在其中一個裏面. 例如: Promise.resolve(merge({ ... }, { ... })).

下面示例中的配置級函數也是如此:

webpack.config.js

const commonConfig = { ... };

const productionConfig = { ... };

const developmentConfig = { ... };

module.exports = env => {
  switch(env) {
    case 'development':
      return merge(commonConfig, developmentConfig);
    case 'production':
      return merge(commonConfig, productionConfig);
    default:
      throw new Error('No matching configuration was found!');
  }
}

你能夠經過 webpack --env development選擇你想要的配置假如你使用了 webpack-cli.

mergeWithCustomize({ customizeArray, customizeObject })(...configuration | [...configuration])

若是你須要更多的靈活性,merge行爲能夠定製每一個字段以下:

const { mergeWithCustomize } = require('webpack-merge');

const output = mergeWithCustomize(
  {
    customizeArray(a, b, key) {
      if (key === 'extensions') {
        return _.uniq([...a, ...b]);
      }

      // 回到默認的合併
      return undefined;
    },
    customizeObject(a, b, key) {
      if (key === 'module') {
        // 自定義合併
        return _.merge({}, a, b);
      }

      // 回到默認的合併
      return undefined;
    }
  }
)(object1, object2, object3, ...);

例如,若是前面的代碼僅使用object1和object2調用,而object1爲:

{
    foo1: ['object1'],
    foo2: ['object1'],
    bar1: { object1: {} },
    bar2: { object1: {} },
}

object2

{
    foo1: ['object2'],
    foo2: ['object2'],
    bar1: { object2: {} },
    bar2: { object2: {} },
}

而後對數組類型的每一個屬性調用 customizeArray,即:

customizeArray(["object1"], ["object2"], "foo1");
customizeArray(["object1"], ["object2"], "foo2");

對對象類型的每一個屬性調用 customizeObject,即:

customizeObject({ object1: {} }, { object2: {} }, bar1);
customizeObject({ object1: {} }, { object2: {} }, bar2);

customizeArray and customizeObject

customizeArraycustomizeObject 提供小策略 mergeWithCustomize. 他們支持字段名append, prepend, replace, 和通配符.

const { mergeWithCustomize, customizeArray, customizeObject } = require('webpack-merge');

const output = mergeWithCustomize({
  customizeArray: customizeArray({
    'entry.*': 'prepend'
  }),
  customizeObject: customizeObject({
    entry: 'prepend'
  })
})(object1, object2, object3, ...);

unique(<field>, <fields>, field => field)

unique 使用了一種策略來強制配置中的惟一性. 當你想要肯定只有一個插件的時候,它是最有用的.

第一個<field>是用於查找重複項的配置屬性。

<fields> 表示在對每一個副本運行field =>field函數時應該唯一的值

const { mergeWithCustomize, unique } = require("webpack-merge");

const output = mergeWithCustomize({
  customizeArray: unique(
    "plugins",
    ["HotModuleReplacementPlugin"],
    plugin => plugin.constructor && plugin.constructor.name
  )
})(
  {
    plugins: [new webpack.HotModuleReplacementPlugin()]
  },
  {
    plugins: [new webpack.HotModuleReplacementPlugin()]
  }
);

// 輸出只包含一個HotModuleReplacementPlugin如今和它的
// 將是最後一個插件實例.

mergeWithRules

爲支持高級合併需求(即在加載器內合併), mergeWithRules包含容許匹配字段和應用匹配策略的附加語法。考慮下面的完整示例:

const a = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [{ loader: "style-loader" }, { loader: "sass-loader" }]
      }
    ]
  }
};
const b = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: "style-loader",
            options: {
              modules: true
            }
          }
        ]
      }
    ]
  }
};
const result = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: "style-loader",
            options: {
              modules: true
            }
          },
          { loader: "sass-loader" }
        ]
      }
    ]
  }
};

assert.deepStrictEqual(
  mergeWithRules({
    module: {
      rules: {
        test: "match",
        use: {
          loader: "match",
          options: "replace"
        }
      }
    }
  })(a, b),
  result
);

它的工做方式是,您應該使用 match(或CustomizeRule)註釋字段以進行匹配。匹配(若是您正在使用TypeScript)匹配您的配置結構,而後使用特定的策略來定義如何轉換特定的字段。

Using with TypeScript

webpack-merge 支持開箱即用的TypeScript。你應該按照如下方式將配置類型從webpack傳遞給它:

import { Configuration } from "webpack";
import { merge } from "webpack-merge";

const config = merge<Configuration>({...}, {...});

...

Development

  1. nvm use
  2. npm i
  3. npm run build -- --watch in one terminal
  4. npm t -- --watch in another one

Before contributing, please open an issue where to discuss.

Further Information and Support

查看 SurviveJS - Webpack 來更深刻地挖掘webpack。這本免費的書普遍地使用了webpack-merge,並向您展現瞭如何組合您的配置來保持它的可維護性。

若是您須要具體的幫助,我也能夠做爲顧問。我能夠在提升設置的可維護性方面作出特別的貢獻,同時加速它並指出更好的實踐。除了提升開發人員的生產力以外,這項工做還會在減小應用程序大小和加載時間方面對產品的最終用戶產生影響。

參考

基本經常使用的方法場景就這些了,更完整的用法能夠直接查閱文檔

webpack-merge

webpack-chain

使用鏈式API去生成簡化webpack 版本2-4配置的修改.

這個文檔對應於webpack-chain的v5版本。有關之前的版本,請參閱:

注意:雖然webpack-chain在Neutrino中被普遍使用,可是這個包是徹底獨立的,能夠被任何項目使用

Introduction

webpack's核心配置基於建立和修改一個可能很笨拙的JavaScript對象. 雖然這對於單個項目的配置來講是能夠的,可是嘗試在項目之間共享這些對象會使後續的修改變得混亂,由於您須要對底層對象結構有深刻的理解才能進行這些更改.

webpack-chain嘗試經過提供一個可連接的或連貫的API來建立和修改webpack配置來改進這個過程. API的關鍵部分能夠經過用戶指定的名稱引用,這有助於標準化如何跨項目修改配置.

經過下面的示例能夠更容易地解釋這一點。

Installation

webpack-chain 須要Node.js v6.9或更高. webpack-chain也只建立用於webpack版本 2, 3, 和4的配置對象.

您可使用Yarn或npm(任選一種)安裝此軟件包:

Yarn

yarn add --dev webpack-chain

npm

npm install --save-dev webpack-chain

Getting Started

一旦你使用webpack-chain替代, 你能夠建立一個webpack配置. 對於本指南, 咱們的例子基礎配置 webpack.config.js在項目的頂層目錄

// 須要webpack-chain模塊。此模塊導出單個
// 用於建立配置API的構造函數
const Config = require('webpack-chain');

// 使用新的API實例化配置
const config = new Config();

// 使用chain API進行配置更改.
// 每一個API調用跟蹤對存儲配置的更改.

config
  // 與入口點交互
  .entry('index')
  .add('src/index.js')
  .end()
  // 修改輸出設置
  .output
  .path('dist')
  .filename('[name].bundle.js');

// 建立可在之後修改的命名規則
config.module
  .rule('lint')
  .test(/\.js$/)
  .pre()
  .include
  .add('src')
  .end()
  // 甚至建立命名的使用(加載器)
  .use('eslint')
  .loader('eslint-loader')
  .options({
    rules: {
      semi: 'off'
    }
  });

config.module
  .rule('compile')
  .test(/\.js$/)
  .include
  .add('src')
  .add('test')
  .end()
  .use('babel')
  .loader('babel-loader')
  .options({
    presets: [
      ['@babel/preset-env', { modules: false }]
    ]
  });

// 也建立命名插件!
config
  .plugin('clean')
  .use(CleanPlugin, [['dist'], { root: '/dir' }]);

// 導出完成的配置對象以供webpack使用
module.exports = config.toConfig();

共享配置也很簡單。只需導出配置並調用.toConfig()便可在傳遞到webpack以前

// webpack.core.js
const Config = require('webpack-chain');
const config = new Config();

// 使配置在目標之間共享
// ...

module.exports = config;

// webpack.dev.js
const config = require('./webpack.core');

// Dev-specific configuration
// ...
module.exports = config.toConfig();

// webpack.prod.js
const config = require('./webpack.core');

// Production-specific configuration
// ...
module.exports = config.toConfig();

ChainedMap

在 webpack-chain核心API接口之一是 ChainedMap. 一個ChainedMap 操做相似於JavaScript Map, 能夠方便地連接和生成配置. 若是一個屬性被標記爲 ChainedMap, 它將具備以下所述的API和方法:

除非另有說明,這些方法將返回 ChainedMap, 容許您連接這些方法.

// 從映射中刪除全部條目.
clear()
// 從給定其鍵的映射中刪除單個條目
// key: *
delete(key)
// 從位於對應鍵的映射中獲取值.
// key: *
// returns: value
get(key)
// 從位於對應鍵的映射中獲取值.
// 若是缺乏鍵,則將鍵設置爲函數fn的結果.
// key: *
// fn: Function () -> value
// returns: value
getOrCompute(key, fn)
// 在`key`位置緩存的Map設置值.
// key: *
// value: *
set(key, value)
// 返回 `true` 或 `false` 取決於Map是否設定了一個特定的key.
// key: *
// returns: Boolean
has(key)
// 返回映射中存儲的全部值的數組.
// returns: Array
values()
// 返回備份映射中全部條目的對象,其中鍵是對象屬性,以及與鍵對應的值。若是支持映射爲空,將返回「undefined」。
// 這將根據屬性的名稱排序,若是值是使用.before() 或者 .after()的ChainedMap.
// returns: Object, undefined if empty
entries()
// 提供一個映射其屬性和值的對象
// 做爲鍵和值導入備份映射.
// 您還能夠提供一個數組做爲第二個參數
// 用於避免合併的屬性名稱
// obj: Object
// omit: Optional Array
merge(obj, omit)
// 根據當前配置上下文執行函數
// handler: Function -> ChainedMap
  // 給ChainedMap實例一個參數的函數
batch(handler)
// 有條件地執行函數以繼續配置
// condition: Boolean
// whenTruthy: Function -> ChainedMap
  // 在條件爲真時調用,給定ChainedMap實例的單個參數
// whenFalsy: Optional Function -> ChainedMap
  // 條件不可靠時調用,給定ChainedMap實例的單個參數
when(condition, whenTruthy, whenFalsy)

ChainedSet

webpack-chain中的另外一個核心API接口是 ChainedSet. ChainedSet操做相似於JavaScript Set,便於連接和生成配置.若是一個屬性被標記爲 ChainedSet, 它將有一個API和方法描述以下:

除非另有說明,這些方法將返回 ChainedMap, 容許您連接這些方法.

// Set末尾添加/追加一個值.
// value: *
add(value)
// Set開頭添加/追加一個值.
// value: *
prepend(value)
// Set刪除全部值.
clear()
// Set移除特定的值.
// value: *
delete(value)
// 返回 `true` 或 `false` 取決於Map是否設定了一個特定的key
// value: *
// returns: Boolean
has(value)
// 返回backing Set包含值的數組
// returns: Array
values()
// 將給定數組鏈接到backing Set.
// arr: Array
merge(arr)
// 根據當前配置上下文執行函數
// handler: Function -> ChainedSet
  // 給ChainedSet實例一個參數的函數
batch(handler)
// 有條件地執行函數以繼續配置
// condition: Boolean
// whenTruthy: Function -> ChainedSet
  // 在條件爲真時調用,給定ChainedSet實例的單個參數
// whenFalsy: Optional Function -> ChainedSet
  // 在條件不可靠時調用,給定ChainedSet實例的單個參數
when(condition, whenTruthy, whenFalsy)

Shorthand methods

有許多快捷方法可使用與快捷方法名相同的鍵設置ChainedMap上的值。例如,devServer.hot是一種速記法,因此它能夠被用做:

// 在ChainedMap上設置值的一種速記方法
devServer.hot(true);

// 這就等於:
devServer.set('hot', true);

快捷的方法是可鏈的,所以調用它將返回原始實例,從而容許您繼續進行鏈操做

Config

建立一個新的配置對象。

const Config = require('webpack-chain');

const config = new Config();

在API中移動到更深的點將改變所修改內容的上下文。您能夠經過再次引用頂級配置或調用.end()向上移動一級回到更高的上下文.若是您熟悉jQuery,那麼.end()的工做原理與此相似。除非另有指定,不然全部API調用都將在當前上下文返回API實例。這樣,若是須要,就能夠連續地將API調用鏈起來。

有關對全部速記和低級方法有效的特定值的詳細信息,請參考在 webpack docs hierarchy.

Config : ChainedMap

Config shorthand methods

config
  .amd(amd)
  .bail(bail)
  .cache(cache)
  .devtool(devtool)
  .context(context)
  .externals(externals)
  .loader(loader)
  .name(name)
  .mode(mode)
  .parallelism(parallelism)
  .profile(profile)
  .recordsPath(recordsPath)
  .recordsInputPath(recordsInputPath)
  .recordsOutputPath(recordsOutputPath)
  .stats(stats)
  .target(target)
  .watch(watch)
  .watchOptions(watchOptions)

Config entryPoints

// Backed at config.entryPoints : ChainedMap
config.entry(name) : ChainedSet

config
  .entry(name)
  .add(value)
  .add(value)

config
  .entry(name)
  .clear()

// Using low-level config.entryPoints:

config.entryPoints
  .get(name)
  .add(value)
  .add(value)

config.entryPoints
  .get(name)
  .clear()

Config output: shorthand methods

config.output : ChainedMap

config.output
  .auxiliaryComment(auxiliaryComment)
  .chunkFilename(chunkFilename)
  .chunkLoadTimeout(chunkLoadTimeout)
  .crossOriginLoading(crossOriginLoading)
  .devtoolFallbackModuleFilenameTemplate(devtoolFallbackModuleFilenameTemplate)
  .devtoolLineToLine(devtoolLineToLine)
  .devtoolModuleFilenameTemplate(devtoolModuleFilenameTemplate)
  .filename(filename)
  .hashFunction(hashFunction)
  .hashDigest(hashDigest)
  .hashDigestLength(hashDigestLength)
  .hashSalt(hashSalt)
  .hotUpdateChunkFilename(hotUpdateChunkFilename)
  .hotUpdateFunction(hotUpdateFunction)
  .hotUpdateMainFilename(hotUpdateMainFilename)
  .jsonpFunction(jsonpFunction)
  .library(library)
  .libraryExport(libraryExport)
  .libraryTarget(libraryTarget)
  .path(path)
  .pathinfo(pathinfo)
  .publicPath(publicPath)
  .sourceMapFilename(sourceMapFilename)
  .sourcePrefix(sourcePrefix)
  .strictModuleExceptionHandling(strictModuleExceptionHandling)
  .umdNamedDefine(umdNamedDefine)

Config resolve: shorthand methods

config.resolve : ChainedMap

config.resolve
  .cachePredicate(cachePredicate)
  .cacheWithContext(cacheWithContext)
  .enforceExtension(enforceExtension)
  .enforceModuleExtension(enforceModuleExtension)
  .unsafeCache(unsafeCache)
  .symlinks(symlinks)

Config resolve alias

config.resolve.alias : ChainedMap

config.resolve.alias
  .set(key, value)
  .set(key, value)
  .delete(key)
  .clear()

Config resolve modules

config.resolve.modules : ChainedSet

config.resolve.modules
  .add(value)
  .prepend(value)
  .clear()

Config resolve aliasFields

config.resolve.aliasFields : ChainedSet

config.resolve.aliasFields
  .add(value)
  .prepend(value)
  .clear()

Config resolve descriptionFields

config.resolve.descriptionFields : ChainedSet

config.resolve.descriptionFields
  .add(value)
  .prepend(value)
  .clear()

Config resolve extensions

config.resolve.extensions : ChainedSet

config.resolve.extensions
  .add(value)
  .prepend(value)
  .clear()

Config resolve mainFields

config.resolve.mainFields : ChainedSet

config.resolve.mainFields
  .add(value)
  .prepend(value)
  .clear()

Config resolve mainFiles

config.resolve.mainFiles : ChainedSet

config.resolve.mainFiles
  .add(value)
  .prepend(value)
  .clear()

Config resolveLoader

config.resolveLoaderAPI 和config.resolve 相同,添加了如下內容:

Config resolveLoader moduleExtensions

config.resolveLoader.moduleExtensions : ChainedSet

config.resolveLoader.moduleExtensions
  .add(value)
  .prepend(value)
  .clear()

Config resolveLoader packageMains

config.resolveLoader.packageMains : ChainedSet

config.resolveLoader.packageMains
  .add(value)
  .prepend(value)
  .clear()

Config performance: shorthand methods

config.performance : ChainedMap

config.performance
  .hints(hints)
  .maxEntrypointSize(maxEntrypointSize)
  .maxAssetSize(maxAssetSize)
  .assetFilter(assetFilter)

Configuring optimizations: shorthand methods

config.optimization : ChainedMap

config.optimization
  .concatenateModules(concatenateModules)
  .flagIncludedChunks(flagIncludedChunks)
  .mergeDuplicateChunks(mergeDuplicateChunks)
  .minimize(minimize)
  .namedChunks(namedChunks)
  .namedModules(namedModules)
  .nodeEnv(nodeEnv)
  .noEmitOnErrors(noEmitOnErrors)
  .occurrenceOrder(occurrenceOrder)
  .portableRecords(portableRecords)
  .providedExports(providedExports)
  .removeAvailableModules(removeAvailableModules)
  .removeEmptyChunks(removeEmptyChunks)
  .runtimeChunk(runtimeChunk)
  .sideEffects(sideEffects)
  .splitChunks(splitChunks)
  .usedExports(usedExports)

Config optimization minimizers

// Backed at config.optimization.minimizers
config.optimization
  .minimizer(name) : ChainedMap

Config optimization minimizers: adding

注意:不要使用new建立最小化插件,由於這將爲你完成。

config.optimization
  .minimizer(name)
  .use(WebpackPlugin, args)

// Examples

config.optimization
  .minimizer('css')
  .use(OptimizeCSSAssetsPlugin, [{ cssProcessorOptions: { safe: true } }])

// 最小化插件也能夠根據它們的路徑指定,這樣在插件或webpack配置最終不會被使用的狀況下,就能夠跳過昂貴的require()。
config.optimization
  .minimizer('css')
  .use(require.resolve('optimize-css-assets-webpack-plugin'), [{ cssProcessorOptions: { safe: true } }])

Config optimization minimizers: modify arguments

config.optimization
  .minimizer(name)
  .tap(args => newArgs)

// Example
config.optimization
  .minimizer('css')
  .tap(args => [...args, { cssProcessorOptions: { safe: false } }])

Config optimization minimizers: modify instantiation

config.optimization
  .minimizer(name)
  .init((Plugin, args) => new Plugin(...args));

Config optimization minimizers: removing

config.optimization.minimizers.delete(name)

Config plugins

// Backed at config.plugins
config.plugin(name) : ChainedMap

Config plugins: adding

注意:不要使用new來建立插件,由於這將爲您完成。

config
  .plugin(name)
  .use(WebpackPlugin, args)

// Examples

config
  .plugin('hot')
  .use(webpack.HotModuleReplacementPlugin);

// 最小化插件也能夠根據它們的路徑指定,這樣在插件或webpack配置最終不會被使用的狀況下,就能夠跳過昂貴的require()。
config
  .plugin('env')
  .use(require.resolve('webpack/lib/EnvironmentPlugin'), [{ 'VAR': false }]);

Config plugins: modify arguments

config
  .plugin(name)
  .tap(args => newArgs)

// Example
config
  .plugin('env')
  .tap(args => [...args, 'SECRET_KEY']);

Config plugins: modify instantiation

config
  .plugin(name)
  .init((Plugin, args) => new Plugin(...args));

Config plugins: removing

config.plugins.delete(name)

Config plugins: ordering before

指定當前插件上下文應該在另外一個已命名插件以前操做。不能在同一個插件上同時使用.before()和.after()。

config
  .plugin(name)
    .before(otherName)

// Example

config
  .plugin('html-template')
    .use(HtmlWebpackTemplate)
    .end()
  .plugin('script-ext')
    .use(ScriptExtWebpackPlugin)
    .before('html-template');

Config plugins: ordering after

指定當前的插件上下文應該在另外一個命名的插件以後操做。不能在同一個插件上同時使用.before()和.after()。

config
  .plugin(name)
    .after(otherName)

// Example

config
  .plugin('html-template')
    .after('script-ext')
    .use(HtmlWebpackTemplate)
    .end()
  .plugin('script-ext')
    .use(ScriptExtWebpackPlugin);

Config resolve plugins

// Backed at config.resolve.plugins
config.resolve.plugin(name) : ChainedMap

Config resolve plugins: adding

注意:不要使用new來建立插件,由於這將爲您完成。

config.resolve
  .plugin(name)
  .use(WebpackPlugin, args)

Config resolve plugins: modify arguments

config.resolve
  .plugin(name)
  .tap(args => newArgs)

Config resolve plugins: modify instantiation

config.resolve
  .plugin(name)
  .init((Plugin, args) => new Plugin(...args))

Config resolve plugins: removing

config.resolve.plugins.delete(name)

Config resolve plugins: ordering before

指定當前插件上下文應該在另外一個已命名插件以前操做。不能在同一個解析插件上同時使用.before()和.after()。

config.resolve
  .plugin(name)
    .before(otherName)

// Example

config.resolve
  .plugin('beta')
    .use(BetaWebpackPlugin)
    .end()
  .plugin('alpha')
    .use(AlphaWebpackPlugin)
    .before('beta');

Config resolve plugins: ordering after

指定當前的插件上下文應該在另外一個命名的插件以後操做。不能在同一個解析插件上同時使用.before()和.after()。

config.resolve
  .plugin(name)
    .after(otherName)

// Example

config.resolve
  .plugin('beta')
    .after('alpha')
    .use(BetaWebpackTemplate)
    .end()
  .plugin('alpha')
    .use(AlphaWebpackPlugin);

Config node

config.node : ChainedMap

config.node
  .set('__dirname', 'mock')
  .set('__filename', 'mock');

Config devServer

config.devServer : ChainedMap

Config devServer allowedHosts

config.devServer.allowedHosts : ChainedSet

config.devServer.allowedHosts
  .add(value)
  .prepend(value)
  .clear()

Config devServer: shorthand methods

config.devServer
  .bonjour(bonjour)
  .clientLogLevel(clientLogLevel)
  .color(color)
  .compress(compress)
  .contentBase(contentBase)
  .disableHostCheck(disableHostCheck)
  .filename(filename)
  .headers(headers)
  .historyApiFallback(historyApiFallback)
  .host(host)
  .hot(hot)
  .hotOnly(hotOnly)
  .https(https)
  .inline(inline)
  .info(info)
  .lazy(lazy)
  .noInfo(noInfo)
  .open(open)
  .openPage(openPage)
  .overlay(overlay)
  .pfx(pfx)
  .pfxPassphrase(pfxPassphrase)
  .port(port)
  .progress(progress)
  .proxy(proxy)
  .public(public)
  .publicPath(publicPath)
  .quiet(quiet)
  .setup(setup)
  .socket(socket)
  .staticOptions(staticOptions)
  .stats(stats)
  .stdin(stdin)
  .useLocalIp(useLocalIp)
  .watchContentBase(watchContentBase)
  .watchOptions(watchOptions)

Config module

config.module : ChainedMap

Config module: shorthand methods

config.module : ChainedMap

config.module
  .noParse(noParse)

Config module rules: shorthand methods

config.module.rules : ChainedMap

config.module
  .rule(name)
    .test(test)
    .pre()
    .post()
    .enforce(preOrPost)

Config module rules uses (loaders): creating

config.module.rules{}.uses : ChainedMap

config.module
  .rule(name)
    .use(name)
      .loader(loader)
      .options(options)

// Example

config.module
  .rule('compile')
    .use('babel')
      .loader('babel-loader')
      .options({ presets: ['@babel/preset-env'] });

Config module rules uses (loaders): modifying options

config.module
  .rule(name)
    .use(name)
      .tap(options => newOptions)

// Example

config.module
  .rule('compile')
    .use('babel')
      .tap(options => merge(options, {
        plugins: ['@babel/plugin-proposal-class-properties']
      }));

Config module rules oneOfs (conditional rules):

config.module.rules{}.oneOfs : ChainedMap<Rule>

config.module
  .rule(name)
    .oneOf(name)

// Example

config.module
  .rule('css')
    .oneOf('inline')
      .resourceQuery(/inline/)
      .use('url')
        .loader('url-loader')
        .end()
      .end()
    .oneOf('external')
      .resourceQuery(/external/)
      .use('file')
        .loader('file-loader')

Config module rules oneOfs (conditional rules): ordering before

指定上下文的當前上下文應該在另外一個已命名的上下文以前操做。.before()和.after()不能同時使用。

config.module
  .rule(name)
    .oneOf(name)
      .before()

// Example

config.module
  .rule('scss')
    .test(/\.scss$/)
    .oneOf('normal')
      .use('sass')
        .loader('sass-loader')
        .end()
      .end()
    .oneOf('sass-vars')
      .before('normal')
      .resourceQuery(/\?sassvars/)
      .use('sass-vars')
        .loader('sass-vars-to-js-loader')

Config module rules oneOfs (conditional rules): ordering after

指定上下文的當前上下文應該在另外一個已命名的上下文以後操做。.before()和.after()不能同時使用。

config.module
  .rule(name)
    .oneOf(name)
      .after()

// Example
config.module
  .rule('scss')
    .test(/\.scss$/)
    .oneOf('vue')
      .resourceQuery(/\?vue/)
      .use('vue-style')
        .loader('vue-style-loader')
        .end()
      .end()
    .oneOf('normal')
      .use('sass')
        .loader('sass-loader')
        .end()
      .end()
    .oneOf('sass-vars')
      .after('vue')
      .resourceQuery(/\?sassvars/)
      .use('sass-vars')
        .loader('sass-vars-to-js-loader')

Merging Config

webpack-chain支持將對象合併到與佈局相似的配置實例中。請注意,這不是一個webpack配置對象,可是您能夠在將一個webpack配置對象提供給webpack-chain以前轉換它以匹配它的佈局。

config.merge({ devtool: 'source-map' });

config.get('devtool') // "source-map"
config.merge({
  [key]: value,

  amd,
  bail,
  cache,
  context,
  devtool,
  externals,
  loader,
  mode,
  parallelism,
  profile,
  recordsPath,
  recordsInputPath,
  recordsOutputPath,
  stats,
  target,
  watch,
  watchOptions,

  entry: {
    [name]: [...values]
  },

  plugin: {
    [name]: {
      plugin: WebpackPlugin,
      args: [...args],
      before,
      after
    }
  },

  devServer: {
    [key]: value,

    clientLogLevel,
    compress,
    contentBase,
    filename,
    headers,
    historyApiFallback,
    host,
    hot,
    hotOnly,
    https,
    inline,
    lazy,
    noInfo,
    overlay,
    port,
    proxy,
    quiet,
    setup,
    stats,
    watchContentBase
  },

  node: {
    [key]: value
  },

  optimization: {
    concatenateModules,
    flagIncludedChunks,
    mergeDuplicateChunks,
    minimize,
    minimizer,
    namedChunks,
    namedModules,
    nodeEnv,
    noEmitOnErrors,
    occurrenceOrder,
    portableRecords,
    providedExports,
    removeAvailableModules,
    removeEmptyChunks,
    runtimeChunk,
    sideEffects,
    splitChunks,
    usedExports,
  },

  performance: {
    [key]: value,

    hints,
    maxEntrypointSize,
    maxAssetSize,
    assetFilter
  },

  resolve: {
    [key]: value,

    alias: {
      [key]: value
    },
    aliasFields: [...values],
    descriptionFields: [...values],
    extensions: [...values],
    mainFields: [...values],
    mainFiles: [...values],
    modules: [...values],

    plugin: {
      [name]: {
        plugin: WebpackPlugin,
        args: [...args],
        before,
        after
      }
    }
  },

  resolveLoader: {
    [key]: value,

    alias: {
      [key]: value
    },
    aliasFields: [...values],
    descriptionFields: [...values],
    extensions: [...values],
    mainFields: [...values],
    mainFiles: [...values],
    modules: [...values],
    moduleExtensions: [...values],
    packageMains: [...values],

    plugin: {
      [name]: {
        plugin: WebpackPlugin,
        args: [...args],
        before,
        after
      }
    }
  },

  module: {
    [key]: value,

    rule: {
      [name]: {
        [key]: value,

        enforce,
        issuer,
        parser,
        resource,
        resourceQuery,
        test,

        include: [...paths],
        exclude: [...paths],

        oneOf: {
          [name]: Rule
        },

        use: {
          [name]: {
            loader: LoaderString,
            options: LoaderOptions,
            before,
            after
          }
        }
      }
    }
  }
})

Conditional configuration

在使用ChainedMap和ChainedSet實例時,可使用When執行條件配置。您必須爲when()指定一個表達式,該表達式將被評估爲真實或錯誤. 若是表達式爲真,則第一個函數參數將與當前連接實例的實例一塊兒調用。您能夠選擇提供第二個函數,以便在條件爲falsy時調用,該函數也提供當前連接實例.

// 示例:只在生產過程當中添加minify插件
config
  .when(process.env.NODE_ENV === 'production', config => {
    config
      .plugin('minify')
      .use(BabiliWebpackPlugin);
  });
// 示例:只在生產過程當中添加minify插件
// 不然設置devtool爲source-map
config
  .when(process.env.NODE_ENV === 'production',
    config => config.plugin('minify').use(BabiliWebpackPlugin),
    config => config.devtool('source-map')
  );

Inspecting generated configuration

您可使用如下config.toString()命令檢查生成的webpack配置 . 這將生成一個stringified版本的配置,帶有關於命名規則、使用方法和插件的註釋提示:

config
  .module
    .rule('compile')
      .test(/\.js$/)
      .use('babel')
        .loader('babel-loader');

config.toString();

/*
{
  module: {
    rules: [
      /* config.module.rule('compile') */
      {
        test: /\.js$/,
        use: [
          /* config.module.rule('compile').use('babel') */
          {
            loader: 'babel-loader'
          }
        ]
      }
    ]
  }
}
*/

默認狀況下,生成的字符串不能直接用做真正的webpack配置,若是它包含了須要的對象和插件.爲了生成可用的配置,您能夠經過設置一個特殊的__expression屬性來定製對象和插件是怎麼分層的

const sass = require('sass');
sass.__expression = `require('sass');

class MyPlugin {}
MyPlugin.__expression = `require('my-plugin')`;

function myFunction () {}
myFunction.__expression = `require('my-function')`;

config
  .plugin('example')
    .use(MyPlugin, [{ fn: myFunction, implementation: sass, }]);

config.toString();

/*
{
  plugins: [
    new (require('my-plugin'))({
      fn: require('my-function'),
      implementation: require('sass')
    })
  ]
}
*/

經過路徑指定的插件將自動生成它們的require()語句:

config
  .plugin('env')
  .use(require.resolve('webpack/lib/ProvidePlugin'), [{ jQuery: 'jquery' }])

config.toString();

/*
{
  plugins: [
    new (require('/foo/bar/src/node_modules/webpack/lib/EnvironmentPlugin.js'))(
      {
        jQuery: 'jquery'
      }
    )
  ]
}
*/

您還能夠將toString做爲配置的靜態方法調用,以便在字符串化以前修改配置對象。

Config.toString({
  ...config.toConfig(),
  module: {
    defaultRules: [
      {
        use: [
          {
            loader: 'banner-loader',
            options: { prefix: 'banner-prefix.txt' },
          },
        ],
      },
    ],
  },
})
{
  plugins: [
    /* config.plugin('foo') */
    new TestPlugin()
  ],
  module: {
    defaultRules: [
      {
        use: [
          {
            loader: 'banner-loader',
            options: {
              prefix: 'banner-prefix.txt'
            }
          }
        ]
      }
    ]
  }
}

參考

基本經常使用的方法場景就這些了,更完整的用法能夠直接查閱文檔

webpack-chain

相關文章
相關標籤/搜索