Babel Compat-Data 深度指南:支撑 @babel/preset-env 插件决策的兼容性数据包
【免费下载链接】babel🐠 Babel is a compiler for writing next generation JavaScript.项目地址: https://gitcode.com/gh_mirrors/ba/babel
@babel/compat-data 是 Babel 编译器生态中用于"确定需要哪些 Babel 插件"的兼容性数据包(compat-data),它以一份份 JSON 数据文件记录每个语法/API 特性在 Chrome、Firefox、Safari、Node.js、Electron 等各目标环境中的最低支持版本。@babel/preset-env 与 @babel/helper-compilation-targets 正是基于这份数据,结合 browserslist 目标查询,自动决定哪些插件需要开启、哪些可以跳过。读完本文,你将掌握该数据包的结构、四个数据文件的含义与消费方式、在项目中的安装使用,以及它在 Babel 源码中的实际调用链。
一、什么是 @babel/compat-data
@babel/compat-data是 Babel 官方维护的一个"零逻辑"数据包:它自身不含任何转换逻辑,只以 JSON 形式维护一张"特性 → 各环境最低支持版本"的映射表。它的设计目标在 README.md 中概括为一句话:"The compat-data to determine required Babel plugins"——即"用于确定所需 Babel 插件的兼容性数据"。
在 package.json 中可以看到它的完整定位:
- 包名:
@babel/compat-data,版本8.0.0,MIT 许可; - 描述:
The compat-data to determine required Babel plugins; - 关键词:
babel、compat-table、compat-data; - 导出入口(
exports字段)公开了 4 个数据子模块,分别对应data/目录下的 4 个 JSON 文件。
它的核心价值在于:把"某个 Babel 转换插件对应的语法特性,在哪些环境版本中已经原生支持"这一事实集中管理,让@babel/preset-env等上层工具可以纯粹地做版本比较,而无需把兼容性信息硬编码在插件代码里。数据以版本号的形式存在于 data/plugins.json 等文件中,例如transform-unicode-sets-regex在 Chrome 112、Firefox 116、Safari 17、Node.js 20 起才原生支持,因此当targets指定的浏览器版本低于这些值时,preset-env 就会决定启用该转换插件。
二、安装与基本使用
根据 README.md,该包可用 npm 或 yarn 安装:
npm install --save @babel/compat-data或使用 yarn:
yarn add @babel/compat-data注意,@babel/compat-data是运行时数据依赖,建议以--save写入dependencies(而不是devDependencies),因为生成代码或运行期解析目标环境时需要读取这些 JSON 数据。
安装完成后,可以直接引用其公开的子模块入口:
// 读取各转换插件的最低支持版本表 const plugins = require("@babel/compat-data/plugins"); // 读取 ES Modules 原生支持版本表(es6.module) const nativeModules = require("@babel/compat-data/native-modules"); // 读取插件之间的覆盖关系 const overlappingPlugins = require("@babel/compat-data/overlapping-plugins"); // 读取 bugfix 插件的最低支持版本表 const pluginBugfixes = require("@babel/compat-data/plugin-bugfixes");这些入口映射定义在 package.json 的exports字段中:
| 子模块导出 | 对应数据文件 |
|---|---|
@babel/compat-data/plugins | data/plugins.json |
@babel/compat-data/native-modules | data/native-modules.json |
@babel/compat-data/overlapping-plugins | data/overlapping-plugins.json |
@babel/compat-data/plugin-bugfixes | data/plugin-bugfixes.json |
@babel/compat-data/package.json | 包自身的package.json |
三、四个数据文件的结构与语义
@babel/compat-data的全部数据都位于 data/ 目录下,共 4 个 JSON 文件。下面逐一说明它们的结构与用途。
1. plugins.json:语法特性的最低支持版本表
这是数据包的核心文件,格式为{ "插件名": { 环境名: 最低支持版本, ... } }。以 data/plugins.json 中的真实条目为例:
{ "transform-regexp-modifiers": { "chrome": "125", "opera": "111", "edge": "125", "firefox": "132", "node": "23", "samsung": "27", "electron": "31.0" }, "transform-unicode-sets-regex": { "chrome": "112", "opera": "98", "edge": "112", "firefox": "116", "safari": "17", "node": "20", "deno": "1.32", "ios": "17", "samsung": "23", "opera_mobile": "75", "electron": "24.0" } }每条记录的含义是:当目标环境的版本低于表中对应值时,该语法特性尚未被原生支持,需要启用对应的 Babel 转换插件;反之则可跳过转换,减少输出代码的体积。
文件中的键除了常规的transform-*插件外,还包含以bugfix/为前缀的条目(如bugfix/transform-v8-static-class-fields-redefine-readonly)。这些是 Babel 7.9+ 引入的"精准修复"型插件:当某个常规插件(如transform-class-properties)被选中时,preset-env 会优先用更小范围的 bugfix 插件替代整体转换,只修复特定引擎的已知 bug,从而让大部分现代浏览器继续使用原生语法。
2. native-modules.json:ES Modules 原生支持版本表
该文件记录的是各环境中ES Modules(es6.module)的原生支持版本,data/native-modules.json 内容如下:
{ "es6.module": { "chrome": "61", "and_chr": "61", "edge": "16", "firefox": "60", "and_ff": "60", "node": "13.2.0", "opera": "48", "op_mob": "45", "safari": "10.1", "ios": "10.3", "samsung": "8.2", "android": "61", "electron": "2.0" } }它的特殊用途是支撑targets.esmodules配置:当用户在@babel/preset-env中设置targets: { esmodules: true }时,@babel/helper-compilation-targets会读取这张表,把目标环境自动限定为"支持原生 ES Modules"的浏览器集合。从源码 src/index.ts 可以看到这一消费方式:
const ESM_SUPPORT = browserModulesData["es6.module"];随后在esmodules处理逻辑中,将表中每个浏览器转换为"浏览器 >= 版本"的 browserslist 查询(见 src/index.ts),并对已解析出的目标版本逐一做esmodules过滤(deno 与 ie 被排除、无 ESM 支持记录的浏览器被删除),最终得到一份"支持 ES Modules"的目标集合。
3. overlapping-plugins.json:插件覆盖关系表
该文件记录"常规插件 → 可替代它的 bugfix 插件"的映射关系,data/overlapping-plugins.json 完整内容如下:
{ "transform-async-to-generator": ["bugfix/transform-async-arrows-in-class"], "transform-parameters": [ "bugfix/transform-edge-default-parameters", "bugfix/transform-safari-id-destructuring-collision-in-function-expression" ], "transform-function-name": ["bugfix/transform-edge-function-name"], "transform-block-scoping": [ "bugfix/transform-safari-block-shadowing", "bugfix/transform-safari-for-shadowing" ], "transform-destructuring": [ "bugfix/transform-safari-rest-destructuring-rhs-array" ], "transform-template-literals": ["bugfix/transform-tagged-template-caching"], "transform-optional-chaining": [ "bugfix/transform-v8-spread-parameters-in-optional-chaining" ], "transform-class-properties": [ "bugfix/transform-v8-static-class-fields-redefine-readonly", "bugfix/transform-firefox-class-in-computed-class-key", "bugfix/transform-safari-class-field-initializer-scope" ] }这张表的意义在于:例如transform-class-properties对应 3 个不同的 bugfix 插件,分别针对 V8(Chrome/Node 中静态类字段重定义 readonly 的 bug)、Firefox(计算类键中的类)和 Safari(类字段初始化器作用域)。当预设需要转换类属性时,可以依据这张表把大而全的整体转换,替换为只针对特定引擎小问题的精准修复,从而让支持原生语法的环境跳过转换、减少代码膨胀。
4. plugin-bugfixes.json:bugfix 插件的支持版本表
该文件记录每个bugfix/transform-*插件的最低支持版本,结构同plugins.json。以 data/plugin-bugfixes.json 中的条目为例:
{ "bugfix/transform-async-arrows-in-class": { "chrome": "55", "opera": "42", "edge": "15", "firefox": "52", "safari": "11", "node": "7.6", "deno": "1", "ios": "11", "samsung": "6", "opera_mobile": "42", "electron": "1.6" }, "bugfix/transform-safari-id-destructuring-collision-in-function-expression": { "chrome": "49", "opera": "36", "edge": "14", "firefox": "2", "safari": "16.3", "node": "6", "deno": "1", "ios": "16.3", "samsung": "5" } }注意观察:同一个 bugfix 插件的"最低支持版本"在不同环境中差异很大——例如bugfix/transform-safari-id-destructuring-collision-in-function-expression只对 Safari 16.3 以下、iOS 16.3 以下的环境有意义,而 Chrome/Firefox 早在远古版本就已正确实现。这正是 bugfix 插件的精髓:精准修复特定引擎的 bug,而不是一揽子降级所有环境。@babel/helper-compilation-targets在筛选插件时,会把 bugfix 插件与常规插件放在同一张版本表中统一比较(见下文调用链)。
四、在 Babel 源码中的实际调用链
@babel/compat-data的价值要通过消费者体现。仓库中最核心的消费者是@babel/helper-compilation-targets(@babel/preset-env的目标解析底层)。下面梳理它的实际使用方式。
1. 插件筛选:filter-items.ts
packages/babel-helper-compilation-targets/src/filter-items.ts 在文件开头直接导入数据:
import pluginsCompatData from "@babel/compat-data/plugins" with { type: "json" };其核心逻辑filterItems遍历plugins.json中的每一个特性,调用isRequired判断在当前targets下该插件是否必需:
export function isRequired( name: string, targets: Targets, { compatData = pluginsCompatData, includes, excludes } = {}, ) { if (excludes?.has(name)) return false; if (includes?.has(name)) return true; return !targetsSupported(targets, compatData[name]); }而targetsSupported(同文件第 12-56 行)把目标的版本与数据表中的最低实现版本逐一比较:取目标环境在support表(即 compat-data)中的最低实现版本,若目标版本低于实现版本则视为"不支持、需要转换"。若目标的targets为空对象,则直接返回false(意味着无目标时不做任何跳过判断)。
2. 目标解析:index.ts 与 browserslist
packages/babel-helper-compilation-targets/src/index.ts 是getTargets的入口实现,它同样导入 native-modules 数据:
import browserModulesData from "@babel/compat-data/native-modules" with { type: "json" };整体流程可以概括为:
- 校验并规范化
targets输入(validateTargetNames、semverifyTarget),支持node: true/node: "current"等特殊取值(src/index.ts); - 若未显式指定
targets或browsers,则自动从process.env.BROWSERSLIST、BROWSERSLIST_CONFIG或 browserslist 配置文件解析查询,兜底使用["defaults"](src/index.ts); - 若设置了
esmodules: true,用native-modules.json的es6.module表推导出浏览器查询(src/index.ts); - 通过 browserslist 解析查询得到各环境最低版本(
resolveTargetsCached使用LRUCache缓存结果,容量 64); - 最后合并目标,输出规范化的
Targets对象。
解析结果最终会交给filterItems,结合plugins.json/plugin-bugfixes.json决定启用哪些插件。
3. 调试输出:getInclusionReasons
@babel/helper-compilation-targets还导出getInclusionReasons(定义于 src/debug.ts,经 src/index.ts 对外导出)。当使用 preset-env 的debug: true选项时,会调用它解释"为什么某个插件被包含/排除",其依据同样是 compat-data 中每个特性的最低支持版本与目标版本的比较结果。这也是排查"为什么我的代码被转换了"时的第一手线索。
五、数据从何而来:生成脚本与数据源
@babel/compat-data的数据并非手工维护,而是通过脚本从权威数据源生成。在 package.json 的scripts字段中定义了build-data任务:
"build-data": "./scripts/download-compat-table.sh && node ./scripts/build-data.mjs && node ./scripts/build-modules-support.mjs && node ./scripts/build-bugfixes-targets.mjs"它依次执行:
download-compat-table.sh:下载 ECMAScript 兼容性表(compat-table)数据;build-data.mjs:将兼容性表按特性映射为"插件 → 最低支持版本";build-modules-support.mjs:生成 ES Modules 支持数据;build-bugfixes-targets.mjs:生成 bugfix 插件的目标版本数据。
其中特性与插件的对应关系维护在 scripts/data/plugin-features.mjs 中。该文件开头有一段重要警告:"Plugin ordering is important. Don't reorder this file"(插件顺序很重要,请勿随意重排),并在注释中说明了排序约束的原因,例如:
// https://github.com/babel/babel/issues/11278 // transform-parameters should run before object-rest-spread即transform-parameters必须在object-rest-spread之前运行,否则会产生错误输出。这个顺序文件同时记录了更细粒度的特性映射,例如transform-parameters对应 "default function parameters"、"rest parameters" 等多个 compat-table 特性项,并可通过exclude排除不支持的子特性(如new Function()支持)。包的其他 devDependencies(@mdn/browser-compat-data、core-js-compat、electron-to-chromium)也用于在生成过程中处理 MDN 数据、core-js 模块支持与 Chromium/Electron 版本换算。
一个值得注意的细节:Chromium 与 Electron
@babel/compat-data的数据中同时出现electron字段(如transform-unicode-sets-regex的electron: "24.0")。这是因为 Electron 的 JS 引擎能力与 Chromium 版本直接相关,仓库中提供了 scripts/chromium-to-electron.mjs 负责把 Chromium 版本映射为对应的 Electron 版本,从而在数据生成阶段就为 Electron 这一目标环境填充支持版本。
六、与 preset-env 配合的典型用法
虽然普通项目很少直接消费@babel/compat-data,但它间接决定了@babel/preset-env的行为。典型用法是在 Babel 配置中声明目标环境:
{ "presets": [ [ "@babel/preset-env", { "targets": { "chrome": "80", "firefox": "75", "node": "14" }, "debug": true } ] ] }当targets使用 browserslist 查询(如"> 0.5%, last 2 versions, not dead")时,getTargets会先借助 browserslist 解析出各环境的最低版本,再与plugins.json中的数据比对;当使用esmodules: true时,则会以native-modules.json的es6.module为基准。开启debug: true后,控制台会打印getInclusionReasons提供的"哪些插件因哪个环境版本而被启用"的详细说明——这份说明的数据来源正是本文介绍的四个 JSON 文件。
七、总结
@babel/compat-data虽是一个"小而专"的数据包,却是 Babel 自动按目标环境裁剪转换范围的关键基石:
- 4 个 JSON 数据文件(plugins.json、native-modules.json、overlapping-plugins.json、plugin-bugfixes.json)分别覆盖常规插件、ES Modules、插件覆盖关系与 bugfix 插件;
- 消费端
@babel/helper-compilation-targets通过filterItems/isRequired/targetsSupported完成"目标版本 vs 最低支持版本"的比较决策,见 src/filter-items.ts; - 生成链路由
build-data脚本从 compat-table、MDN 等数据源构建,特性到插件的顺序映射维护在 scripts/data/plugin-features.mjs; - 在 README.md 中确认的安装方式为
npm install --save @babel/compat-data或yarn add @babel/compat-data。
理解这份数据包,也就理解了 preset-env "按需转换"的决策依据:目标环境原生支持的语法不转换,不支持的才转换——@babel/compat-data正是那张决定"是否支持"的权威对照表。
【免费下载链接】babel🐠 Babel is a compiler for writing next generation JavaScript.项目地址: https://gitcode.com/gh_mirrors/ba/babel
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考