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

相关文章
相关标签/搜索