配置文件
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
配置文件类型
Babel 提供两种独立的配置文件格式,可同时使用或单独使用。
History
| Version | Changes |
|---|---|
v7.21.0 | Support .babelrc.cts and babel.config.cts (Experimental) |
v7.8.0 | Support .babelrc.mjs and babel.config.mjs |
v7.7.0 | Support .babelrc.json, .babelrc.cjs, babel.config.json, babel.config.cjs |
-
项目级配置
babel.config.*文件,支持以下扩展名:.json、.js、.cjs、.mjs、.cts
-
文件相对配置
.babelrc.*文件,支持以下扩展名:.json、.js、.cjs、.mjs、.cts- 无扩展名的
.babelrc文件 package.json文件中带"babel"键的配置
项目级配置
Babel 7.x 新增了"根目录"概念,默认为当前工作目录。项目级配置中,Babel 会自动在该根目录下搜索 babel.config.json 文件或使用支持扩展名的等效文件。用户也可通过显式设置"configFile"值覆盖默认搜索行为。
项目级配置文件独立于物理存储位置,特别适合需要广泛应用的配置场景。它允许插件和预设轻松作用于 node_modules 或符号链接包中的文件——这些在 Babel 6.x 中曾是难以配置的痛点。
项目级配置的主要缺点是依赖工作目录。在 monorepo 中若工作目录非仓库根目录时,使用会较繁琐。具体配置示例请参阅monorepo文档。
通过设置"configFile"为 false 可禁用项目级配置。
文件相对配置
Babel 通过从编译文件"filename"开始向上遍历目录(受下述限制约束),加载 .babelrc.json 或使用支持扩展名的等效文件。这种机制支持为包内子模块创建独立配置,且文件相对配置会合并到项目级配置之上,适合特定覆盖场景(也可通过"overrides"实现)。
使用文件相对配置需注意以下边界情况:
-
搜索遇到含
package.json的目录即停止,因此相对配置仅作用于单个包内 -
被编译文件"filename"必须位于"babelrcRoots"指定的包内,否则跳过搜索
这意味着:
-
.babelrc.json文件仅作用于所属包内的文件 -
非 Babel '根目录'包中的
.babelrc.json文件默认被忽略,除非通过"babelrcRoots"显式启用
多包 monorepo 配置详见monorepo文档。通过设置"babelrc"为 false 可禁用文件相对配置。
6.x 与 7.x 的 .babelrc 加载差异
Babel 6.x 用户需特别注意 7.x 新增的上述两个边界条件限制,这些限制旨在解决 6.x 的常见陷阱:
-
6.x 中
.babelrc文件会意外应用到node_modules依赖 -
当用户期望
.babelrc文件能像处理普通依赖一样生效时,它们却无法应用于符号链接的node_modules依赖。 -
即使
node_modules依赖中的插件和预设通常未安装,甚至可能与当前 Babel 编译版本不兼容,.babelrc文件仍会被检测到。
这些情况主要会影响采用 monorepo 结构的用户,因为如果存在
.babelrc
packages/
mod1/
package.json
src/index.js
mod2/
package.json
src/index.js
配置将被完全忽略,因为它跨越了包边界。
一种替代方案是在每个子包中创建使用 "extends" 的 .babelrc 文件
{ "extends": "../../.babelrc" }
遗憾的是,这种方式可能略显重复,且根据 Babel 的使用方式,可能需要设置 "babelrcRoots"。
鉴于此,更可取的做法是将 .babelrc 重命名为项目级 "babel.config.json"。如前述项目级配置部分所述,这可能需要显式设置 "configFile",因为若工作目录不正确,Babel 将无法找到配置文件。
支持的文件扩展名
如配置文件类型部分所述,Babel 可使用 Node.js 原生支持的任何文件扩展名进行配置:
-
babel.config.json和.babelrc.json被解析为 JSON5 格式,需包含符合 Babel 接受的选项格式的对象。自v7.7.0起支持。我们建议优先使用此文件类型:当需要根据构建条件动态生成复杂配置时,JS 配置文件非常实用。但缺点是 JS 配置无法静态分析,会降低可缓存性、影响 lint 检查及 IDE 自动补全等。由于
babel.config.json和.babelrc.json是静态 JSON 文件,允许 Webpack 等使用 Babel 的工具安全缓存编译结果,这能显著提升构建性能。 -
babel.config.cjs和.babelrc.cjs允许以 CommonJS 格式定义配置(使用module.exports)。自v7.7.0起支持。 -
babel.config.mjs和.babelrc.mjs使用原生 ECMAScript 模块格式。需 Node.js 13.2+ 支持(旧版本可通过--experimental-modules标志启用)。请注意原生 ESM 是异步的(这也是import()始终返回 Promise 的原因!):因此当同步调用 Babel 时,.mjs配置文件会抛出错误。自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.ts和babel.config.mts文件。
JavaScript 配置文件可导出对象,或导出被调用时返回配置的函数。函数式配置具备特殊能力,因其可访问 Babel 暴露的 API。详见配置函数 API。
出于兼容性考虑,.babelrc 是 .babelrc.json 的别名。
Monorepo 项目
采用 Monorepo 结构的代码仓库通常包含多个子包,因此经常会遇到文件相对配置和配置文件加载的限制条件。本节旨在帮助用户理解如何配置 Monorepo 项目。
在 Monorepo 环境中,核心需要理解的是 Babel 将工作目录视为逻辑上的"根目录"。如果您希望在特定子包中运行 Babel 工具而不影响整个仓库,这会导致问题。
另外,您还需确定是使用.babelrc.json文件还是仅用中心化的babel.config.json。在 Babel 7 中,不再像 Babel 6 那样必须使用.babelrc.json进行子目录特殊配置,因此通常更推荐使用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,例如:
cd packages/some-package;
babel src -d dist
此时 Babel 使用的"根目录"_并非_您的 Monorepo 根目录,因此无法定位到babel.config.json文件。
如果所有构建脚本都在仓库根目录执行则没有问题,但如果在子包内运行 Babel 编译流程,则需告知 Babel 配置文件的位置。推荐使用"rootMode"选项并设置为"upward",这将使 Babel 从工作目录向上搜索babel.config.json文件,并将其所在位置设为"根目录"。
测试配置是否生效的有效方法:若使用 JavaScript 格式的babel.config.json,可在文件中加入console.log()调用 - 首次加载时日志会输出。
设置方式因项目而异,以下是常见场景示例:
CLI
babel --root-mode upward src -d lib
@babel/register
require("@babel/register")({
rootMode: "upward",
});
Webpack
module: {
rules: [
{
loader: "babel-loader",
options: {
rootMode: "upward",
},
},
];
}
Jest
Jest 通常安装在 Monorepo 根目录,此时可能无需额外配置;但若按子包安装则配置会变得复杂。
核心解决方案是创建自定义 jest 转换器文件,通过包装babel-jest的默认行为来设置参数,例如:
module.exports = require("babel-jest").default.createTransformer({
rootMode: "upward",
});
保存此文件后,需在 Jest 配置的transform 选项中用该文件替换babel-jest:
"transform": {
"^.+\\.jsx?$": "./path/to/wrapper.js"
},
因此所有 JavaScript 文件都将通过启用了该选项的 babel-jest 版本进行处理。
使用 babel-jest < 27 版本时,必须省略 .default 部分:require("babel-jest").createTransformer({ ...。
其他工具
虽然存在大量工具,但核心要求是:如果工作目录不是 monorepo 根目录,就必须启用 rootMode 选项。
子包中的 .babelrc.json 文件
与 babel.config.json 文件必须位于"根"目录类似,
.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" 选项:
babelrcRoots: [
".",
"packages/*",
],
这样 Babel 会将所有 packages/* 包视为允许加载 .babelrc.json 文件的区域,同时包含原始仓库根目录。
配置函数 API
JS 配置文件可以导出一个函数,该函数接收 config API 作为参数:
module.exports = function(api) {
return {};
};
api 配置 API 对象包含以下属性或方法:
api.version
类型:string
加载配置文件的 Babel 版本号字符串。
api.cache
JavaScript 配置的优势在于可动态计算配置,但缺点是增加了缓存难度。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"),这样缓存条目只能是true或false。
api.env(...)
由于 NODE_ENV 是切换行为的常用方式,Babel 专门为此提供了 API 函数。
该 API 用于快速检测 Babel 加载时使用的"环境名称",
若未设置其他覆盖环境,此值会考虑 NODE_ENV。
该函数有以下几种形式:
-
api.env("production")当envName === "production"时返回true -
api.env(["development", "test"])当["development", "test"].includes(envName)时返回true -
api.env()返回当前envName字符串 -
api.env(envName => envName.startsWith("test-"))当环境名称以 "test-" 开头时返回true
:::注意
此函数内部使用上文提到的 api.cache,确保 Babel 感知到构建依赖特定的 envName。
请勿将其与 api.cache.forever() 或 api.cache.never() 同时使用。
:::
api.caller(cb)
此 API 用于访问传递给 Babel 的 caller 数据。由于同一进程中可能有多个 Babel 实例运行不同 caller 值,
该 API 的设计会像 api.env() 那样自动配置 api.cache。
回调函数的首个参数即为 caller 值,最佳实践是结合类似
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 通过以下方式实现:
module.exports = function(api) {
api.assertVersion("^7.2");
return {
// ...
};
};