Skip to main content

配置 Babel

Babel 可以配置!许多其他工具也有类似的配置:ESLint(.eslintrc)、Prettier(.prettierrc)。

🌐 Babel can be configured! Many other tools have similar configs: ESLint (.eslintrc), Prettier (.prettierrc).

所有 Babel API 的 选项 都可以使用。不过,如果某个选项需要 JavaScript,你可能想使用一个 JavaScript 配置文件。

🌐 All Babel API options are allowed. However, if the option requires JavaScript, you may want to use a JavaScript configuration file.

你的用例是什么?​

🌐 What's your use case?

  • 你正在使用大仓?
  • 你想编译 node_modules 吗?

babel.config.json 是给你的!

  • 你的配置仅适用于项目的单个部分?

.babelrc.json 是给你的!

  • Guy Fieri 是你的英雄?

我们建议使用 babel.config.json 格式。

babel.config.json​

在你项目的根目录下创建一个名为 babel.config.json 的文件,内容如下(package.json 所在的位置)。

🌐 Create a file called babel.config.json with the following content at the root of your project (where the package.json is).

babel.config.json
{
"presets": [...],
"plugins": [...]
}

查看 babel.config.json 文档 以了解更多配置选项。

🌐 Check out the babel.config.json documentation to see more configuration options.

.babelrc.json​

在你的项目中创建一个名为 .babelrc.json 的文件,并写入以下内容。

🌐 Create a file called .babelrc.json with the following content in your project.

.babelrc.json
{
"presets": [...],
"plugins": [...]
}

查看 .babelrc 文档 了解更多配置选项。

🌐 Check out the .babelrc documentation to see more configuration options.

package.json​

或者,你也可以选择在 package.json 中通过使用 babel 键来指定你的 .babelrc.json 配置,如下所示:

🌐 Alternatively, you can choose to specify your .babelrc.json config from within package.json using the babel key like so:

package.json
{
"name": "my-package",
"version": "1.0.0",
"babel": {
"presets": [ ... ],
"plugins": [ ... ],
}
}

JavaScript 配置文件​

🌐 JavaScript configuration files

你也可以使用 JavaScript 编写 babel.config.js(就像我们正在做的)和 .babelrc.js 文件:

🌐 You can also write babel.config.js (like we're doing), and .babelrc.js files using JavaScript:

babel.config.js
module.exports = function (api) {
api.cache(true);

const presets = [ ... ];
const plugins = [ ... ];

return {
presets,
plugins
};
}

你可以访问任何 Node.js API,例如基于进程环境的动态配置:

🌐 You are allowed to access any Node.js APIs, for example a dynamic configuration based on the process environment:

babel.config.js
module.exports = function (api) {
api.cache(true);

const presets = [ ... ];
const plugins = [ ... ];

if (process.env["ENV"] === "prod") {
plugins.push(...);
}

return {
presets,
plugins
};
}

你可以在专门的文档中了解更多关于 JavaScript 配置文件的信息

🌐 You can read more about JavaScript configuration files in the dedicated documentation

使用命令行接口(@babel/cli)​

🌐 Using the CLI (@babel/cli)

Shell
babel --plugins @babel/plugin-transform-arrow-functions script.js

查看一下 babel-cli 文档 来了解更多配置选项。

🌐 Check out the babel-cli documentation to see more configuration options.

使用 API(@babel/core)​

🌐 Using the API (@babel/core)

JavaScript
require("@babel/core").transformSync("code", {
plugins: ["@babel/plugin-transform-arrow-functions"],
});

查看 babel-core 文档 了解更多配置选项。

🌐 Check out the babel-core documentation to see more configuration options.

🌐 Print effective configs

你可以告诉 Babel 在给定的输入路径上打印生效的配置

🌐 You can tell Babel to print effective configs on a given input path

# *nix or WSL
BABEL_SHOW_CONFIG_FOR=./src/myComponent.jsx npm start

BABEL_SHOW_CONFIG_FOR 接受绝对路径和相对 文件 路径。如果是相对路径,将从 cwd 解析。

一旦 Babel 处理了由 BABEL_SHOW_CONFIG_FOR 指定的输入文件,Babel 就会把有效的配置打印到控制台。下面是一个示例输出:

🌐 Once Babel processes the input file specified by BABEL_SHOW_CONFIG_FOR, Babel will print effective configs to the console. Here is an example output:

Babel configs on "/path/to/cwd/src/index.js" (ascending priority):
config /path/to/cwd/babel.config.json
{
"sourceType": "script",
"plugins": [
"@foo/babel-plugin-1"
],
"extends": "./my-extended.js"
}

config /path/to/cwd/babel.config.json .env["test"]
{
"plugins": [
[
"@foo/babel-plugin-3",
{
"noDocumentAll": true
},
]
]
}

config /path/to/cwd/babel.config.json .overrides[0]
{
"test": "src/index.js",
"sourceMaps": true
}

config /path/to/cwd/.babelrc
{}

programmatic options from @babel/cli
{
"sourceFileName": "./src/index.js",
"presets": [
"@babel/preset-env"
],
"configFile": "./my-config.js",
"caller": {
"name": "@babel/cli"
},
"filename": "./src/index.js"
}

Babel 会按优先级从低到高打印有效的配置来源。以上面的例子来说,优先级是:

🌐 Babel will print effective config sources ordered by ascending priority. Using the example above, the priority is:

babel.config.json < .babelrc < programmatic options from @babel/cli

换句话说,babel.config.json 会被 .babelrc 覆盖,而 .babelrc 会被程序选项覆盖。

🌐 In other words, babel.config.json is overwritten by .babelrc, and .babelrc is overwritten by programmatic options.

对于每个配置源,Babel 会按照优先级升序打印适用的配置项(例如 overrides 和 env)。通常,每个配置源至少有一个配置项——配置的根内容。如果你配置了 overrides 或 env,Babel 不会在根目录打印它们,而会输出一个单独的配置项,标题为 .overrides[index],其中 index 是该配置项的位置。这有助于判断该配置项是否对输入有效,以及它会覆盖哪些配置。

🌐 For each config source, Babel prints applicable config items (e.g. overrides and env) in the order of ascending priority. Generally each config sources has at least one config item -- the root content of configs. If you have configured overrides or env, Babel will not print them in the root, but will instead output a separate config item titled as .overrides[index], where index is the position of the item. This helps determine whether the item is effective on the input and which configs it will override.

如果你的输入被 ignore 或 only 忽略,Babel 会显示这个文件被忽略。

🌐 If your input is ignored by ignore or only, Babel will print that this file is ignored.

Babel 如何合并配置项​

🌐 How Babel merges config items

Babel 的配置合并相对简单。当选项存在且其值不是 undefined 时,新的选项会覆盖已有的选项。不过,也有一些特殊情况:

🌐 Babel's configuration merging is relatively straightforward. Options will overwrite existing options when they are present and their value is not undefined. There are, however, a few special cases:

  • 对于 assumptions、parserOpts 和 generatorOpts,对象是合并的,而不是被替换的。
  • 对于 plugins 和 presets,它们是根据插件/预设对象或函数本身的身份结合入口的名称来替换的。

选项(插件/预设除外)合并​

🌐 Option (except plugin/preset) merging

例如,考虑一个配置:

🌐 As an example, consider a config with:

JavaScript
{
sourceType: "script",
assumptions: {
setClassFields: true,
iterableIsArray: false
},
env: {
test: {
sourceType: "module",
assumptions: {
iterableIsArray: true,
},
}
}
};

当 NODE_ENV 是 test 时,sourceType 选项将被替换,assumptions 选项将被合并。有效的配置是:

🌐 When NODE_ENV is test, the sourceType option will be replaced and the assumptions option will be merged. The effective config is:

JavaScript
{
sourceType: "module", // sourceType: "script" is overwritten
assumptions: {
setClassFields: true,
iterableIsArray: true, // assumptions are merged by Object.assign
},
}

插件/预设合并​

🌐 Plugin/Preset merging

例如,考虑一个配置:

🌐 As an example, consider a config with:

JavaScript
plugins: [
'./other',
['./plug', { thing: true, field1: true }]
],
overrides: [{
plugins: [
['./plug', { thing: false, field2: true }],
]
}]

overrides 项将会合并到顶层选项上。重要的是,整个 plugins 数组不仅仅是替换顶层选项。合并逻辑会检查 "./plug" 在两种情况下都是相同的插件,然后 { thing: false, field2: true } 会替换原来的选项,最终的配置如下

🌐 The overrides item will be merged on top of the top-level options. Importantly, the plugins array as a whole doesn't just replace the top-level one. The merging logic will see that "./plug" is the same plugin in both cases, and { thing: false, field2: true } will replace the original options, resulting in a config as

JavaScript
plugins: [
'./other',
['./plug', { thing: false, field2: true }],
],

由于合并是基于身份 + 名称的,所以在同一个 plugins/presets 数组中两次使用同名插件被认为是错误的。例如

🌐 Since merging is based on identity + name, it is considered an error to use the same plugin with the same name twice in the same plugins/presets array. For example

JavaScript
plugins: ["./plug", "./plug"];

被认为是一个错误,因为它和 plugins: ['./plug'] 一模一样。此外,即使

🌐 is considered an error, because it's identical to plugins: ['./plug']. Additionally, even

JavaScript
plugins: [["./plug", { one: true }], ["./plug", { two: true }]];

会被认为是错误,因为第二个总是会替换第一个。

🌐 is considered an error, because the second one would just always replace the first one.

如果你真的想要实例化两个独立的插件实例,你必须给每个实例分配一个名字来区分它们。例如:

🌐 If you actually do want to instantiate two separate instances of a plugin, you must assign each one a name to disambiguate them. For example:

JavaScript
plugins: [
["./plug", { one: true }, "first-instance-name"],
["./plug", { two: true }, "second-instance-name"],
];

因为每个实例都被赋予了唯一的名称,因此也被赋予了唯一的身份。

🌐 because each instance has been given a unique name and thus a unique identity.