4

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()代表文件
semvernpm的语义版本器
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调用获得机器的默认网关
joiJavaScript最强大的模式描述语言和数据验证器。
fs-extra添加了未包含在原生fs模块中的文件系统方法,并向fs方法添加了promise支持
Acorn一个小而快速的JavaScript解析器,完全用JavaScript编写。
zlib.jsZLIB.js是ZLIB(RFC1950), DEFLATE(RFC1951), GZIP(RFC1952)和PKZIP在JavaScript实现。

nodejs交互工具库 -- chalk-pipe和chalk

nodejs交互工具库 -- commander和Inquirer

nodejs交互工具库 -- slash, minimist和dotenv, dotenv-expand

nodejs交互工具库 -- hash-sum, deepmerge和yaml-front-matter

nodejs交互工具库 -- resolve和semver

nodejs交互工具库 -- leven, lru cache和portfinder

nodejs交互工具库 -- ora和envinfo

nodejs交互工具库 -- memfs和execa

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

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


Afterward
621 声望62 粉丝

努力去做,对的坚持,静待结果