配置 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
的文件,并输入如下内容。
{
"presets": [...],
"plugins": [...]
}
请参阅 babel.config.json
文档 以了解更多关于配置参数的信息。
.babelrc.json
在你的项目中创建名为 .babelrc.json
的文件,并输入以下内容。
{
"presets": [...],
"plugins": [...]
}
请参阅 .babelrc 文档 以了解更多关于配置参数的信息。
package.json
或者,还可以选择将 .babelrc.json
中的配置信息作为 babel
键(key)的值添加到 package.json
文件中,如下所示:
{
"name": "my-package",
"version": "1.0.0",
"babel": {
"presets": [ ... ],
"plugins": [ ... ],
}
}
用 JavaScript 编写配置文件
你还可以用 JavaScript 来编写 babel.config.js
(就像我们这样) 和 .babelrc.js
文件:
module.exports = function (api) {
api.cache(true);
const presets = [ ... ];
const plugins = [ ... ];
return {
presets,
plugins
};
}
你还可以调用 Node.js 的任何 API,例如基于进程环境进行动态配置:
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
)
babel --plugins @babel/plugin-transform-arrow-functions script.js
请参阅 babel-cli 文档 以了解更多关于配置参数的信息。
使用 API (@babel/core
)
require("@babel/core").transformSync("code", {
plugins: ["@babel/plugin-transform-arrow-functions"],
});
请参阅 babel-core 文档 以了解更多关于配置参数的信息。
Print effective configs
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
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
andgeneratorOpts
, objects are merged, rather than replaced. - 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,
},
}
}
};
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 }],
]
}]
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 }],
],
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"];
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.