配置 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?
-
你正在使用大仓?
¥You are using a monorepo?
-
你想编译
node_modules
?¥You want to compile
node_modules
?
babel.config.json
是给你的!¥
babel.config.json
is for you!
-
你的配置仅适用于项目的单个部分?
¥You have a configuration that only applies to a single part of your project?
.babelrc.json
是给你的!¥
.babelrc.json
is for you!
-
Guy Fieri 是你的英雄?
¥Guy Fieri is your hero?
我们建议使用
babel.config.json
格式。¥We recommend using the
babel.config.json
format.
babel.config.json
在项目的根目录(package.json
所在的位置)创建一个名为 babel.config.json
的文件,其中包含以下内容。
¥Create a file called babel.config.json
with the following content at the root of your project (where the package.json
is).
{
"presets": [...],
"plugins": [...]
}
查看 babel.config.json
documentation 以查看更多配置选项。
¥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.
{
"presets": [...],
"plugins": [...]
}
查看 .babelrc 文档 以查看更多配置选项。
¥Check out the .babelrc documentation to see more configuration options.
package.json
或者,你可以选择使用 babel
键从 package.json
中指定你的 .babelrc.json
配置,如下所示:
¥Alternatively, you can choose to specify your .babelrc.json
config from within package.json
using the babel
key like so:
{
"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:
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:
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
使用 CLI (@babel/cli
)
¥Using the CLI (@babel/cli
)
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
)
require("@babel/core").transformSync("code", {
plugins: ["@babel/plugin-transform-arrow-functions"],
});
查看 babel 核心文档 以查看更多配置选项。
¥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
- Shell
- powershell
# *nix or WSL
BABEL_SHOW_CONFIG_FOR=./src/myComponent.jsx npm start
$env:BABEL_SHOW_CONFIG_FOR = ".srcmyComponent.jsx"; npm start
BABEL_SHOW_CONFIG_FOR
接受绝对和相对文件路径。如果是相对路径,则从 cwd
解析。
¥BABEL_SHOW_CONFIG_FOR
accepts both absolute and relative file paths. If it is a relative path, it will be resolved from 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
,对象被合并,而不是被替换。¥For
assumptions
,parserOpts
andgeneratorOpts
, objects are merged, rather than replaced. -
对于
plugins
和presets
,它们根据插件/预设对象/函数本身的标识结合条目名称进行替换。¥For
plugins
andpresets
, 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:
{
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:
{
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:
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
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
plugins: ["./plug", "./plug"];
会被认为是错误,因为它与 plugins: ['./plug']
相同。此外,即使
¥is considered an error, because it's identical to plugins: ['./plug']
. Additionally, even
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:
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.