Skip to content
/ airpack Public

A better solution for sharing webpack config in multiple projects. It gives webpack the ability to read configs from dependencies and merge them in a more appropriate way.

Notifications You must be signed in to change notification settings

arzyu/airpack

Repository files navigation

airpack

npm package version npm peer dependency version build status

Read this in other languages: English

airpack 是一个 webpack-cli 的包装器。旨在让你更优雅的使用 webpack。

airpack 在 node 加载 webpack-cli 模块时,给 webpack-cli 打上功能增强补丁。这个补丁让 webpack-cli 能按一定的优先级顺序自动从多个位置(项目依赖、项目目录、命令行参数)读取 webpack 配置,然后用更合适的方式合并这些 webpack 配置。

通过这种方式使用 webpack 配置会有很多好处:

  • 项目目录会更干净,只有项目相关的逻辑,没有 .babelrc.*postcss.config.js.eslintrc.*、…,甚至也不需要 webpack.config.*。项目模板化会更方便。可以参看范例项目:react-webpack-playground

  • 使用更少的 devDependencies,依赖列表的长度从一个胳膊缩短到了一根手指,所有与 webpack 配置相关的依赖都放在独立的 webpack-config-* 包中。

  • 使用独立的 webpack-config-* 包更容易管理,版本控制、迭代会更方便,同时也利于分享。将包发布到自己或组织的名下更合适,可以参考范例配置:@arzyu/webpack-config-web。复杂的配置还可以拆分为多个包,airpack 能帮你合并它们。

安装

npm add --save-dev airpack

使用方法与运行机制

# 查看使用帮助
$(npm bin)/airpack --help
Usage: airpack [options] [other-webpack-options]

Options:
  -s, --server                    Run webpack-dev-server
  -c, --config <file|package...>  Specify webpack configs (default: [])
  --no-autoconfig                 Only load webpack configs from '-c, --config ...' option
  --print                         Print webpack configs with paths, without running webpack
  -v, --version                   Print airpack version
  -h, --help                      Print this help

以使用 @arzyu/webpack-config-web 这个 webpack 配置为例,package.json 看起来应该是这样的:

{
  "scripts": {
    "dev": "NODE_ENV=development airpack --server",
    "build": "NODE_ENV=production airpack"
  },
  "devDependencies": {
    "@arzyu/webpack-config-web": "^0.1.3",
    "airpack": "^1.0.1",
    "webpack": "^5.33.2",
    "webpack-cli": "^4.7.2",
    "webpack-dev-server": "^3.11.2"
  },
}
  • npm run dev,启动本地开发服务(调用 webpack serve
  • npm run build,运行打包(调用 webpack

配置文件查找顺序与优先级

使用 airpack 不指定 --no-autoconfig 参数时,它会帮我们自动搜集 webpack 配置,逻辑顺序如下:

  • 查找项目依赖中所有的 webpack-config-* 项目,依次加入配置列表末尾
  • 如果项目根目录中有 webpack.config.* 文件,被 webpack 识别为默认配置的那一个会被追加到配置列表末尾
  • 如果有使用 airpack -c, --config 引入的 webpack 配置文件或包,依次将它们加入配置列表末尾

在配置列表中,靠后的配置优先级更高,在合并时会覆盖前面配置中的项目。

上面的范例中,如果我们运行:

airpack -c file-a.js -c package-b -c package-c/internal

可能会得到这样的配置列表:

[
  "@arzyu/webpack-config-web",
  "webpack.config.js",
  "file-a.js",
  "package-b",
  "package-c/internal"
]

注意:airpack -c package-c/internal 这种引入配置的方式,可以让你在一个包中包含多个 webpack 配置。典型的场景比如在做 electron 相关的开发时,你可以制作一个 webpack-config-electron 包,这个包中写两个配置,webpack-config-eletron/mainwebpack-config-eletron/renderer

如果你不想让 airpack 自动搜集 webpack 配置,可以使用 --no-autoconfig 参数,这种方式必需配合 -c, --config 参数来手动指定配置文件。

airpack --no-autoconfig -c config-a -c config-b

这样,最终的 webpack 配置列表就是 ["config-a", "config-b"]

配置文件合并逻辑

搜集完成 webpack 配置列表,需要对这些配置执行合并操作。

虽然 webpack-cli 有提供 --merge 参数来实现合并配置的功能,但是其合并配置的方式只是简单的把所有的配置合并到一个对象当中,这样 webpack 的多配置功能就无法使用了。所以 airpack 重做了合并逻辑,只合并相同 name 属性的配置对象,再将无 name 属性的配置对象合并到所有其它的配置对象中,具体步骤如下例子。

假定我们搜集到了这样的一个配置列表内容:

[
  { "a": "from a", "x": "override by a" },
  { "b": "from b", "x": "override by b", name: "group_1" },
  { "c": "from c", "x": "override by c", name: "group_2" },
  { "d": "from d", "x": "override by d" },
  { "e": "from e", "x": "override by e", name: "group_1" },
]

Step 1,将所有配置对象按 name 属性分组,组内保持优先顺序:

{
  "undefined": [
    { "a": "from a", "x": "override by a" },
    { "d": "from d", "x": "override by d" }
  ],
  "group_1": [
    { "b": "from b", "x": "override by b", "name": "group_1" },
    { "e": "from e", "x": "override by e", "name": "group_1" }
  ],
  "group_2": [
    { "c": "from c", "x": "override by c", "name": "group_2" }
  ]
}

Step 2,分别合并各个分组:

{
  "undefined": {
    "a": "from a",
    "d": "from d",
    "x": "override by d"
  },
  "group_1": {
    "b": "from b",
    "e": "from e",
    "x": "override by e",
    "name": "group_1"
  },
  "group_2": {
    "c": "from c",
    "x": "override by c",
    "name": "group_2"
  }
}

Step 3,将没有 name 属性的 undefined 分组分别和其它的分组合并,得到最终的 webpack 配置:

[
  {
    "a": "from a",
    "d": "from d",
    "b": "from b",
    "e": "from e",
    "x": "override by e",
    "name": "group_1"
  },
  {
    "a": "from a",
    "d": "from d",
    "c": "from c",
    "x": "override by c",
    "name": "group_2"
  }
]

注意:如果配置列表中所有的配置对象都没有 name 属性,那么所有配置对象会被合并进一个对象,这与 webpack-cli 的合并逻辑相同。

airpack 开发

新版本 webpack-cli 版本适配步骤:

  1. 检查新版本 webpack-cli 适配情况:
$ npm run airpack-check ">4.10.0"

> [email protected] airpack-check /PATH/TO/airpack
> node -r ts-node/register scripts/airpack-check.ts ">4.10.0"

[airpack-check]: Checking [email protected] ...
[airpack-check]: Hash not matched to the target "WebpackCLI.loadConfig"
[airpack-check]: SMd2eWJHlrP/Mnza0CV2+/k965k= <- rCQ126ukG6NldCsqBZkAoKOyC68=
  1. 如有必要,编辑 specs.ts 增加新的适配版本
  2. 如有必要,编辑 adapter.ts 增加新的代码适配器,可借助 AST Explorer 定位代码位置。

License

MIT

About

A better solution for sharing webpack config in multiple projects. It gives webpack the ability to read configs from dependencies and merge them in a more appropriate way.

Topics

Resources

Stars

Watchers

Forks