跳到主要内容

配置 Babel

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

所有 Babel API 参数 都可以被配置。然而,如果该参数需要用到 JavaScript 代码,你可能需要使用 JavaScript 代码版的 配置文件

你的使用场景是什么?

  • 你是否采用的是单一仓库(monorepo)模式?
  • 你是否需要编译 node_modules

那么 babel.config.json 文件可以满足你的的需求!

  • 你的配置文件是否仅适用于项目的某个部分?

那么 .babelrc.json 文件适合你!

  • Guy Fieri is your hero?

我们建议使用 babel.config.json 格式的配置文件。

babel.config.json

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

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

请参阅 babel.config.json 文档 以了解更多关于配置参数的信息。

.babelrc.json

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

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

请参阅 .babelrc 文档 以了解更多关于配置参数的信息。

package.json

或者,还可以选择将 .babelrc.json 中的配置信息作为 babel 键(key)的值添加到 package.json 文件中,如下所示:

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

用 JavaScript 编写配置文件

你还可以用 JavaScript 来编写 babel.config.js (就像我们这样) 和 .babelrc.js 文件:

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

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

return {
presets,
plugins
};
}

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

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 配置文件的信息。

使用 CLI (@babel/cli)

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

请参阅 babel-cli 文档 以了解更多关于配置参数的信息。

使用 API (@babel/core)

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

请参阅 babel-core 文档 以了解更多关于配置参数的信息。

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 accepts both absolute and relative file paths. If it is a relative path, it will be resolved from cwd.

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 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

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

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.

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

How Babel merges config items

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:

  • For assumptions, parserOpts and generatorOpts, objects are merged, rather than replaced.
  • For plugins and presets, they are replaced based on the identity of the plugin/preset object/function itself combined with the name of the entry.

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,
},
}
}
};

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 }],
]
}]

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 }],
],

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"];

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.