尽管 Webpack 还没有启用很多功能,但配置量开始变大。现在你必须要小心你的配置方式,因为你在项目中至少要区分生产和开发两个环境。随着功能的增加,情况只会变得更糟。
使用单个整体配置文件会变得不容易理解,并且可重用性几乎为 0。随着项目需求的增长,您必须找到更有效地管理 Webpack 配置的方法。
管理配置的方法
您可以通过以下方式管理 Webpack 配置:
- 对于每一个环境都使用多个文件来组合配置,通过模块导入共享相同的配置,并通过
--config
参数将 Webpack 指向特定的环境。 - 将配置打包成库,然后使用该库。例如:hjs-webpack、Neutrino、webpack-blocks。
- 将配置转换成工具。例如:create-react-app、kyt、nwb。
- 在单个文件中的维护所有的配置,并在其内部进行分支,使用传入
--env
参数来确定分支走向。本章后面将详细介绍该方法。
可以组合这些方法以创建更高级别的配置,然后由更小的部分组成。然后可以将这些部分添加到库中,然后通过npm使用它,从而可以在多个项目中使用相同的配置。
通过合并来组合配置
如果配置文件被分成不同的部分,则必须以某种方式再次组合它们。通常这意味着合并对象和数组。为了解决 Object.assign
和 Array.concat
存在的问题,我们可以使用 webpack-merge。
webpack-merge 做了两件事:拼接数组并合并对象,而不是简单的覆盖它们。以下示例详细显示了这种特性:
> merge = require("webpack-merge")
...
> merge(
... { a: [1], b: 5, c: 20 },
... { a: [2], b: 10, d: 421 }
... )
{ a: [ 1, 2 ], b: 10, c: 20, d: 421 }
webpack-merge 提供了许多可控的策略,使您能够控制每个字段的行为。它们允许您对于特定的字段进行追加,添加或替换内容。
在组合修改 Webpack 配置的时候,webpack-chain 提供了一个清晰的 API 简化这一过程。
设置 webpack-merge
首先,将 webpack-merge 添加到项目中:
npm install webpack-merge --save-dev
为了达到一定程度的抽象,您可以定义 webpack.config.js 管理一般用途的配置,而使用 webpack.parts.js 来管理特殊部分的配置。以下是从现有代码中提取的基于函数接口的部分配置:
webpack.parts.js
exports.devServer = ({ host, port } = {}) => ({
devServer: {
stats: "errors-only",
host, // 默认为 `localhost`
port, // 默认为 8080
open: true,
overlay: true,
},
});
对于
stats
字段,这种方法也适用于生产环境,stats
的完整选项,请参阅官方文档。
为了引入部分配置,请按照以下代码示例设置 webpack.config.js:
webpack.config.js
const merge = require("webpack-merge");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const parts = require("./webpack.parts");
const commonConfig = merge([
{
plugins: [
new HtmlWebpackPlugin({
title: "Webpack demo",
}),
],
},
]);
const productionConfig = merge([]);
const developmentConfig = merge([
parts.devServer({
// 如果有需要的话,可以在这里定义 host/port
host: process.env.HOST,
port: process.env.PORT,
}),
]);
module.exports = mode => {
if (mode === "production") {
return merge(commonConfig, productionConfig, { mode });
}
return merge(commonConfig, developmentConfig, { mode });
};
注意 webpack.config.js 没有直接返回配置,而是返回了一个捕获 env
参数的函数。该函数根据参数返回配置,并将 env
参数映射到 webpack mode
上。这样做意味着 package.json 需要修改:
package.json
"scripts": {
"start": "webpack-dev-server --env development",
"build": "webpack --env production"
}
完成这些更改后,功能和以前是一样的。但是,这一次,您有扩展的空间,您不必担心如何组合配置的不同部分了。
您可以根据需要扩展 package.json 和 webpack.config.js 的分支,而特定的配置可以放到 webpack.parts.js 中。通过这种方式,你可以做更多的事情,但配置依然条理清晰。
productionConfig
的规模还很小,随着我们进一步扩展配置,它将会增长。
代码中使用的 process 模块是 Node 中的一个全局变量。至于
env
,它还提供了许多其他功能,使您可以获得有关主机系统的更多信息。
理解 --env
尽管 --env
只是允许将字符串传递给配置,但它还有更多的技巧。请考虑以下示例:
package.json
"scripts": {
"start": "webpack-dev-server --env development",
"build": "webpack --env.target production"
},
您应该可以在配置中接收 { target: "production" }
对象,而不是字符串。您可以传递更多的键值对,然后它们会转到该 env
对象下。如果在设置 --env.target
时又设置了 --env foo
,则字符串形式更加优先。Webpack 的命令行交互依赖于 yargs。
组合配置的好处
配置拆分提供了更好的扩展性和复用性。你可以把通用型配置和特殊型配置提取成配置单元,把这些配置单元作为包在不同的项目之间复用。
您还可以将配置作为依赖项进行管理,而不是在多个项目中复制类似的配置。当您的配置升级或者问题修复时,您的所有项目都会同时受益。
每种方法都有其优点和缺点。基于组合的方法是一个很好的起点。就组合而言,每部分的代码量是有限的,很容易阅读。你还可以看看别人是怎么做的,从而找到一些更好的做法。
也许最大的问题在于,你需要知道自己在做什么,而且第一次配置可能会缺乏经验。但这就是一个软件工程问题,它不是 Webpack 所独有的。
您可以随时迭代优化配置单元或者找到更好的配置单元。通过传入配置对象而不是多个参数,您可以在不影响其 API 的情况下更改配置单元的行为,从而根据需要有效地公开配置单元的 API。
配置布局
在这本书中,您所有的配置将会分为两个文件:webpack.config.js 和 webpack.parts.js。前者包含通用型的配置,后者包含一些特殊配置,这样我们可以更方便的管理我们的配置文件。
按环境拆分配置
如果您按环境拆分配置,最终可能会得到如下文件结构:
.
└── config
├── webpack.common.js
├── webpack.development.js
├── webpack.parts.js
└── webpack.production.js
在这种情况下,您将通过 Webpack --config
参数和 module.exports = merge(common, config);
来获得最终的配置环境。
按类别拆分配置
我们可以将特殊配置放到一个文件夹中,按照类别把 webpack.parts.js 拆分成一个个小的配置文件:
.
└── config
├── parts
│ ├── devserver.js
...
│ ├── index.js
│ └── javascript.js
└── ...
这种安排可以更快地找到与特定类别相关的配置。
将配置打包
鉴于所有配置都是 JavaScript,没有什么可以阻止您将其作为包使用。可以打包共享配置,以便您可以跨多个项目使用它。有关如何实现此目标的更多信息,请参阅维护手册。
总结
尽管配置在技术上与以前相同,但是现在已经有足够的扩展性了。
回顾一下:
- 鉴于 Webpack 配置是 JavaScript 代码,我们有很多方法可以管理它。
- 您应该选择一种对您最有意义的方法来组合配置。webpack-merge 提供了一种轻量级的合成方法,但你还可以找到许多其他选项。
- Webpack 的
--env
参数允许您通过终端控制最终的配置结果。在您的接口函数中会接受到这个参数。 - 组合使得配置可以共享。您可以通过这种方式在仓库之间共享它,而不必在每个仓库都维护一个自定义配置。npm 包是一种不错的选择。开发配置和开发其他 JavaScript 代码是相似的。但是,这一次,您可以将您的实践成果打包成包。
本书的下一部分介绍了很多不同的技术,webpack.parts.js 会有许多变化。幸运的是,对 webpack.config.js 的更改仍然很少。