跳至主要内容

配置文件

配置文件类型

Babel 有两种并行的配置文件格式,可以一起使用,也可以独立使用。

历史
版本更改
v7.21.0支持 .babelrc.ctsbabel.config.cts(实验性)
v7.8.0支持 .babelrc.mjsbabel.config.mjs
v7.7.0支持 .babelrc.json.babelrc.cjsbabel.config.jsonbabel.config.cjs
  • 项目级配置
    • babel.config.* 文件,具有以下扩展名:.json.js.cjs.mjs.cts
  • 文件相对配置
    • .babelrc.* 文件,具有以下扩展名:.json.js.cjs.mjs.cts
    • .babelrc 文件,无扩展名。
    • package.json 文件,带有 "babel" 键。

项目级配置

Babel 7.x 中的新功能,Babel 有一个 "根" 目录的概念,默认为当前工作目录。对于项目级配置,Babel 将在此根目录中自动搜索 babel.config.json 文件,或使用 支持的扩展名 的等效文件。或者,用户可以使用显式的 "configFile" 值来覆盖默认的配置文件搜索行为。

因为项目级配置文件与配置文件的物理位置分离,所以它们对于必须广泛应用的配置来说是理想的选择,甚至允许插件和预设轻松应用于 node_modules 中的文件或符号链接的包中,这在 Babel 6.x 中配置起来非常痛苦。

这种项目级配置的主要缺点是,因为它依赖于工作目录,所以如果工作目录不是 monorepo 根目录,那么在 monorepos 中使用它可能会更加痛苦。有关如何在该上下文中使用配置文件的示例,请参阅 monorepo 文档。

也可以通过将 "configFile" 设置为 false 来禁用项目级配置。

文件相对配置

Babel 通过从要编译的 "filename" 开始向上搜索目录结构(受以下警告限制)来加载 .babelrc.json 文件,或使用 支持的扩展名 的等效文件。这很强大,因为它允许您为包的子部分创建独立的配置。文件相对配置也 合并 到项目级配置值之上,这使得它们对于特定覆盖可能很有用,尽管这也可以通过 "overrides" 来完成。

使用文件相对配置时,需要考虑一些边缘情况

  • 一旦找到包含 package.json 的目录,搜索就会停止,因此相对配置仅适用于单个包内。
  • 要编译的 "filename" 必须位于 "babelrcRoots" 包内,否则将完全跳过搜索。

这些警告意味着

  • .babelrc.json 文件适用于其自身包内的文件
  • 除非您使用 "babelrcRoots" 选择加入,否则将忽略不在 Babel“根目录”中的包中的 .babelrc.json 文件。

有关如何配置具有多个包的 monorepos 的更多讨论,请参阅 monorepo 文档。也可以通过将 "babelrc" 设置为 false 来禁用文件相对配置。

6.x 与 7.x .babelrc 加载

来自 Babel 6.x 的用户可能会在 Babel 7.x 中新增的这两个边缘情况下出错。添加这两个限制是为了解决 Babel 6.x 中常见的错误

  • .babelrc 文件应用于 node_modules 依赖项,通常是意外的。
  • 当人们期望 .babelrc 文件像普通依赖项一样工作时,它们无法应用于符号链接的 node_modules
  • 即使 node_modules 依赖项.babelrc 文件中的插件和预设通常未安装,甚至在编译文件的 Babel 版本中可能无效,也会检测到它们。

这些情况主要会导致具有 monorepo 结构的用户出现问题,因为如果您有

.babelrc
packages/
mod1/
package.json
src/index.js
mod2/
package.json
src/index.js

现在将完全忽略该配置,因为它跨越了包边界。

一种替代方法是在每个子包中创建一个 .babelrc,使用 "extends" 作为

.babelrc.json
{ "extends": "../../.babelrc" }

不幸的是,这种方法可能有点重复,并且根据 Babel 的使用方式,可能需要设置 "babelrcRoots"

鉴于此,将 .babelrc 重命名为 项目级“babel.config.json” 可能更可取。如上面的项目级部分所述,这可能需要显式设置 "configFile",因为如果工作目录不正确,Babel 将找不到配置文件。

支持的文件扩展名

配置文件类型 部分所述,可以使用 Node.js 本生支持的任何文件扩展名来配置 Babel

  • babel.config.json.babelrc.json 被解析为 JSON5,并且应该包含与 Babel 接受的 选项 格式匹配的对象。自 v7.7.0 起支持它们。

    我们建议尽可能使用此文件类型:如果您有复杂的配置,这些配置是有条件的或在构建时计算的,那么 JS 配置文件很方便。但是,缺点是 JS 配置的可静态分析性较差,因此对可缓存性、linting、IDE 自动完成等有负面影响。由于 babel.config.json.babelrc.json 是静态 JSON 文件,它允许使用 Babel 的其他工具(如打包器)安全地缓存 Babel 的结果,这可以大大提高构建性能。

  • babel.config.cjs.babelrc.cjs 允许您使用 module.exports 将配置定义为 CommonJS。自 v7.7.0 起支持它们。

  • babel.config.mjs.babelrc.mjs 使用原生 ECMAScript 模块。它们受 Node.js 13.2+(或通过 --experimental-modules 标志的旧版本)支持。请记住,原生 ECMAScript 模块是异步的(这就是 import() 始终返回 promise 的原因!):因此,.mjs 配置文件在同步调用 Babel 时会抛出异常。自 v7.8.0 起支持它们。

  • 当您的 package.json 文件包含 "type": "module" 选项时,babel.config.js.babelrc.js 的行为类似于 .mjs 等效项,否则它们与 .cjs 文件完全相同。

  • babel.config.cts.babelrc.cts 允许您使用 Typescript + CommonJS 定义配置。您必须安装 @babel/preset-typescript,或使用 ts-node 运行 Babel。

    注意

    🚧 此功能是实验性的。在 Node.js ESM 加载器 API 稳定之前,还无法使用 babel.config.tsbabel.config.mts 文件。

JavaScript 配置文件可以导出一个对象,也可以导出一个在调用时返回生成的配置的函数。返回函数的配置被赋予了一些特殊的能力,因为它们可以访问 Babel 本身公开的 API。有关更多信息,请参阅 配置函数 API

注意

出于兼容性原因,.babelrc.babelrc.json 的别名。

Monorepos

Monorepo 结构的存储库通常包含许多包,这意味着它们经常遇到 文件相对配置 和配置文件加载中提到的警告。本节旨在帮助用户了解如何进行 monorepo 配置。

使用 monorepo 设置,需要了解的核心内容是 Babel 将您的工作目录视为其逻辑 "根",如果您想在特定子包中运行 Babel 工具而不希望 Babel 应用于整个存储库,这就会导致问题。

另外,确定是要使用 .babelrc.json 文件还是仅使用中央 babel.config.json 文件也很重要。.babelrc.json 文件不像 Babel 6 中那样需要用于特定于子文件夹的配置,因此在 Babel 7 中通常不需要它们,而是使用 babel.config.json

babel.config.json 文件

任何 monorepo 结构的第一步都应该是在存储库根目录中创建一个 babel.config.json 文件。这将建立 Babel 对存储库基本目录的核心概念。即使您想使用 .babelrc.json 文件来配置每个单独的包,将其作为存储库级选项的位置也很重要。

您通常可以将所有存储库配置放在根 babel.config.json 中。使用 "overrides",您可以轻松指定仅适用于存储库中某些子文件夹的配置,这通常比在整个存储库中创建许多 .babelrc.json 文件更容易遵循。

您可能会遇到的第一个问题是,默认情况下,Babel 希望从设置为其 "根" 的目录中加载 babel.config.json 文件,这意味着如果您创建了一个 babel.config.json,但在单个包中运行 Babel,例如

Shell
cd packages/some-package;
babel src -d dist

在这种情况下,Babel 使用的 "根"不是您的 monorepo 根目录,并且它将无法找到 babel.config.json 文件。

如果您的所有构建脚本都相对于您的存储库根目录运行,那么一切应该已经可以正常工作了,但是如果您正在从子包中运行 Babel 编译过程,则需要告诉 Babel 在哪里查找配置。 有几种方法可以做到这一点,但推荐的方法是使用 "upward""rootMode" 选项,这将使 Babel 从工作目录向上搜索查找您的 babel.config.json 文件,并将使用其位置作为 "root" 值。

测试您的配置是否被检测到的一种有用的方法是,如果它是一个 babel.config.json JavaScript 文件,则在其中放置一个 console.log() 调用:该日志将在 Babel 第一次加载它时执行。

您如何设置此值因项目而异,但以下是一些示例

CLI

Shell
babel --root-mode upward src -d lib

@babel/register

JavaScript
require("@babel/register")({
rootMode: "upward",
});

Webpack

webpack.config.js
module: {
rules: [
{
loader: "babel-loader",
options: {
rootMode: "upward",
},
},
];
}

Jest

Jest 通常安装在 monorepo 的根目录下,可能不需要配置,但如果它是按包安装的,那么配置起来可能会更加复杂。

主要部分是创建一个自定义 jest 转换器文件,该文件包装 babel-jest 的默认行为以设置选项,例如

wrapper.js
module.exports = require("babel-jest").default.createTransformer({
rootMode: "upward",
});

将其保存在某个地方后,您就可以在 Jest 选项中通过 transform 选项 使用该文件来代替 babel-jest

jest.config.js
"transform": {
"^.+\\.jsx?$": "./path/to/wrapper.js"
},

因此所有 JS 文件都将使用启用了该选项的您的 babel-jest 版本进行处理。

注意

使用 babel-jest < 27 时,必须省略 .default 部分:require("babel-jest").createTransformer({ ...

其他

有很多工具,但其核心是,如果工作目录还不是 monorepo 根目录,则需要启用 rootMode 选项。

子包 .babelrc.json 文件

babel.config.json 文件需要位于 "root" 中的方式类似,默认情况下,.babelrc.json 文件必须位于根中。 这意味着,工作目录影响 babel.config.json 加载的方式与影响 .babelrc.json 加载的方式相同。

假设您已经按照上述方法正确加载了 babel.config.json 文件,Babel 将只处理该根包(而不是子包)内的 .babelrc.json 文件,例如

package.json
babel.config.js
packages/
mod/
package.json
.babelrc.json
index.js

编译 packages/mod/index.js 文件不会加载 packages/mod/.babelrc.json,因为此 .babelrc.json 位于子包中,而不是根包中。

要启用对该 .babelrc.json 的处理,您需要使用 babel.config.json 文件中的 "babelrcRoots" 选项来执行

JavaScript
babelrcRoots: [
".",
"packages/*",
],

这样 Babel 会将所有 packages/* 包都视为允许加载 .babelrc.json 文件,以及原始存储库根目录。

配置函数 API

JS 配置文件可以导出一个函数,该函数将传递给配置函数 API

JavaScript
module.exports = function(api) {
return {};
};

api 对象公开了 Babel 本身从其索引模块公开的所有内容,以及特定于配置文件的 API

api.version

类型:string

加载配置文件的 Babel 版本的版本字符串。

api.cache

JS 配置很棒,因为它们可以动态计算配置,但缺点是它使缓存变得更加困难。 Babel 希望避免在每次编译文件时都重新执行配置函数,因为那样它还需要重新执行该配置中引用的任何插件和预设函数。

为了避免这种情况,Babel 希望配置函数的用户告诉它如何在配置文件中管理缓存。

  • api.cache.forever() - 永久缓存计算出的配置,并且不再调用该函数。
  • api.cache.never() - 不要缓存此配置,并且每次都重新执行该函数。
  • api.cache.using(() => process.env.NODE_ENV) - 根据 NODE_ENV 的值进行缓存。 只要 using 回调返回的值与预期值不同,就会再次调用整个配置函数,并将一个新条目添加到缓存中。
  • api.cache.invalidate(() => process.env.NODE_ENV) - 根据 NODE_ENV 的值进行缓存。 只要 using 回调返回的值与预期值不同,就会再次调用整个配置函数,并将使用结果替换缓存中的所有条目。
  • api.cache(true) - 与 api.cache.forever() 相同
  • api.cache(false) - 与 api.cache.never() 相同

由于实际的回调结果用于检查缓存条目是否有效,因此建议

  • 回调应该小巧且无副作用。
  • 回调应该返回范围尽可能小的值。 例如,上面的 .using(() => process.env.NODE_ENV) 用法并不理想,因为它会根据检测到的 NODE_ENV 值的数量创建未知数量的缓存条目。 使用 .using(() => process.env.NODE_ENV === "development") 会更安全,因为这样缓存条目只能是 truefalse

api.env(...)

由于 NODE_ENV 是一种相当常见的切换行为的方式,因此 Babel 还包含一个专门为此设计的 API 函数。 此 API 用作快速检查加载 Babel 时使用的 "envName" 的方法,如果没有设置其他覆盖环境,则会考虑 NODE_ENV

它有几种不同的形式

  • 如果 envName === "production",则 api.env("production") 返回 true
  • 如果 ["development", "test"].includes(envName),则 api.env(["development", "test"]) 返回 true
  • api.env() 返回当前的 envName 字符串。
  • 如果环境以“test-”开头,则 api.env(envName => envName.startsWith("test-")) 返回 true
注意

此函数在内部使用上面提到的 api.cache 来确保 Babel 知道此构建依赖于特定的 envName。 您不应将其与 api.cache.forever()api.cache.never() 一起使用。

api.caller(cb)

此 API 用作访问已传递给 Babel 的 caller 数据的一种方式。 由于 Babel 的许多实例可能在同一个进程中运行,但具有不同的 caller 值,因此此 API 旨在自动配置 api.cache,其方式与 api.env() 相同。

caller 值作为回调函数的第一个参数提供。 最好将其与以下内容一起使用

JavaScript
function isBabelRegister(caller) {
return !!(caller && caller.name === "@babel/register");
}

module.exports = function(api) {
const isRegister = api.caller(isBabelRegister);

return {
// ...
};
};

根据特定环境切换配置行为。

api.assertVersion(range)

虽然 api.version 通常很有用,但有时声明您的版本会很好。 此 API 提供了一种使用以下方法的简单方法

JavaScript
module.exports = function(api) {
api.assertVersion("^7.2");

return {
// ...
};
};