ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

深入 Babel preset-env 贡献指南:为 `@babel/preset-env` 添加新特性插件与 polyfill 支持

深入 Babel preset-env 贡献指南:为 `@babel/preset-env` 添加新特性插件与 polyfill 支持 深入 Babel preset-env 贡献指南为babel/preset-env添加新特性插件与 polyfill 支持【免费下载链接】babel Babel is a compiler for writing next generation JavaScript.项目地址: https://gitcode.com/gh_mirrors/ba/babelbabel/preset-env是 Babel 生态中按目标环境智能启用转换插件与 polyfill 的核心预设它通过一份特性 → 插件映射数据决定哪些语法需要被编译。本文以 packages/babel-preset-env/CONTRIBUTING.md 为骨架完整讲解当 ECMAScript 新特性被批准进入下一版本时如何为 preset-env 新增插件支持、更新 core-js polyfill 数据与plugins.json兼容表以及如何编写和运行 preset-env 的测试。读完本文你将掌握 preset-env 数据管线的完整工作流能够独立提交一个新特性支持级别的贡献。1. 背景preset-env 的特性 → 插件数据管线在动手添加特性之前先理解 preset-env 的核心数据流这决定了你修改的每一个文件落在链路的哪一环。从当前仓库的源码结构看整个链路大致如下特性描述文件packages/babel-compat-data/scripts/data/plugin-features.mjs 把 compat-table 中的特性名映射到 Babel 插件名并按 ES 版本分块组织es2015、es2016、es2017…。文件头部有明确的警告Plugin ordering is important. Dont reorder this file因为插件执行顺序会影响转换结果。兼容性数据packages/babel-compat-data/data/plugins.json 记录每个插件在各目标引擎chrome、firefox、safari、node、electron 等中的最低支持版本例如transform-explicit-resource-management在chrome: 141、node: 25起才无需转换。运行时筛选preset-env 在 src/plugins-compat-data.ts 中导入babel/compat-data/plugins、plugin-bugfixes与overlapping-plugins再通过filterAvailable过滤掉当前 Babel 版本不存在的插件依据 src/available-plugins.ts最终得到实际可用的插件集合src/filter-items.ts 负责剔除重叠插件与当前 Babel 版本不支持的插件。因此新增一个特性支持本质上是补全上述第 1、2 步的数据并让第 3 步的筛选逻辑自动生效。2. 添加一个新的转换插件支持以 ES2016**为例当 ECMAScript 新特性被 TC39 批准进入正式版本而非 proposal 阶段后贡献的第一步是把它登记到特性映射中。原文档以 ES2016 的指数运算符**为例给出完整操作步骤第一步在 compat-table 中找到该特性对应的条目。在 compat-table 的 es2016 分类中定位到exponentiation (**) operator**运算符。第二步找到负责转换该特性的 Babel 插件。指数运算符对应的插件是babel/plugin-transform-exponentiation-operator该插件源码位于 packages/babel-plugin-transform-exponentiation-operator/src/index.ts。第三步写入 plugin-features.mjs。打开 packages/babel-compat-data/scripts/data/plugin-features.mjs按照插件名 → features 数组的结构新增条目// es2016 babel/plugin-transform-exponentiation-operator: { features: [ exponentiation (**) operator, ], },从当前仓库的plugin-features.mjs可以看到该条目已实际存在于es2016块中且结构完全一致const es2016 { transform-exponentiation-operator: { features: [exponentiation (**) operator], }, };2.1 深入理解 features 映射的高级形态原文档只展示了最简单的一对一映射但真实仓库中的映射远不止这一种形态了解它们能帮你写出正确的贡献字符串简写单个特性名可直接写为字符串例如transform-json-strings: JSON superset、transform-optional-chaining: optional chaining operator (?.)。排除子特性exclude某些转换插件并不覆盖特性的全部语义需要显式排除。例如transform-arrow-functions排除由transform-classes和transform-new-target处理的lexical super binding in constructors、lexical new.target bindingtransform-template-literals排除arbitrary escape sequences in tagged template literals。多特性聚合一个插件可能对应多个特性例如transform-parameters同时覆盖默认参数、剩余参数、解构参数等 4 个特性条目。bugfix 插件replaces / overwrite在es2022块中可以看到bugfix/transform-v8-static-class-fields-redefine-readonly等条目使用replaces: transform-class-properties声明替代关系并用overwrite覆盖特定引擎如 firefox的版本阈值。关键约束文件顶部警告插件顺序很重要。plugin-features.mjs最终通过Object.assign({}, shippedProposal, es2026, es2025, ..., es5)合并见文件末尾现代特性的插件排在前面这是有意为之——preset-env 生成插件列表时遵循该顺序保证es2015Parametertransform-parameters在object-rest-spread之前运行见文件中https://github.com/babel/babel/issues/11278的注释。3. 更新 core-js polyfill 数据新特性若涉及全局对象/内置方法built-in仅做语法转换不够还需要 polyfill 数据。原文档按 core-js 版本分两种情况说明。3.1 core-js2 时代的做法历史流程原文档以 ES2017 的Object.values为例在 compat-table 中找到特性与子特性用/拼接为Object static methods / Object.values在core-js2的modules目录中找到对应模块es7.object.values.js在packages/babel-preset-env/data/corejs2-built-in-features.js中登记特性名与 core-js 模块的映射const es { //... es7.object.values: Object static methods / Object.values }若希望该 built-in 能被useBuiltIns: usage按需引入还需在polyfills/corejs2/built-in-definitions.js中添加 core-js 模块映射。3.2 core-js3 的现状polyfill 管线已整体迁移原文档对 core-js3 的说明很简单只需升级依赖中的core-js-compat版本。而在当前仓库中这条演进已更进一步——useBuiltIns选项与 preset-env 内置的 polyfill 数据已被彻底移除。这一点在 src/normalize-options.ts 中有明确证据if ((opts as any).useBuiltIns) { throw new Error( The useBuiltIns option has been removed. Please use babel-plugin-polyfill-corejs3 instead., ); }也就是说文档中提到的corejs2-built-in-features.js、polyfills/corejs2/built-in-definitions.js、polyfills/corejs3/built-in-definitions.js、polyfills/corejs3/shipped-proposals.js这些历史文件在当前仓库中已不存在。如果今天要贡献 polyfill 数据正确入口是babel-plugin-polyfill-corejs3插件及其数据源core-js-compat而不是 preset-env 本身——这也是当前normalize-options.ts中import corejs3Polyfills from core-js-compat/data.json的原因preset-env 只保留了对core-js-compat数据的引用能力用于 include/exclude 校验实际注入逻辑已交由独立的 polyfill 插件。3.3 当前仓库中仍保留的 proposal 登记入口虽然 built-in 数据已外移但 proposal 语法插件的登记仍在 preset-env 内。查看 src/shipped-proposals.ts它维护着proposalPlugins由shippedProposals选项按目标启用与proposalSyntaxPlugins语法插件独立于编译目标两套集合。当前仓库中这两者均为空集/空数组——这表明目前没有任何已被浏览器广泛支持的 proposal 需要特殊登记。若未来有提案满足条件贡献方式即是在该文件中添加对应插件名。4. 更新plugins.json让新插件进入兼容性数据plugin-features.mjs只是特性语义映射插件能否按目标环境启用取决于 packages/babel-compat-data/data/plugins.json 中的引擎版本数据。该文件由脚本从 compat-table 数据源生成compat-table 数据通过 packages/babel-compat-data/scripts/download-compat-table.sh 按固定 commit 拉取。脚本头部即定义了数据源版本COMPAT_TABLE_COMMIT1bcd416b9f4399c71d3234c06bd0441074195743若本地已有相同 commit 的克隆则直接跳过否则会重新 clone 该 commit 的 compat-table 仓库到build/compat-table。更新COMPAT_TABLE_COMMIT为最新 commit 后运行npm run build-data重新生成数据。如果 compat-table 没有新增相关条目plugins.json将保持不变这也是合并前验证无副作用的方式。plugins.json的典型条目形态当前仓库真实数据如下每个插件对应各引擎的支持版本{ transform-regexp-modifiers: { chrome: 125, opera: 111, edge: 125, firefox: 132, node: 23, samsung: 27, electron: 31.0 } }plugins.json中的electron、deno、ios、rhino等非主流引擎字段以及 data/plugin-bugfixes.json、data/overlapping-plugins.json、data/native-modules.json 同目录数据均由构建脚本统一产出贡献者一般不需要手改而是保证数据源脚本和上游 compat-table 正确。5. 编写与运行测试5.1 运行测试preset-env 的测试运行方式遵循仓库通用规范具体见根目录 CONTRIBUTING.md 中的 Running linting/tests 章节。当前仓库的测试基础配置在 jest.config.tspreset-env 相关测试通过yarn jest packages/babel-preset-env之类的命令即可局部运行。5.2 编写 fixture 测试preset-env 的全部测试位于 packages/babel-preset-env/test/fixtures 目录其测试设置与约定和普通 Babel 插件的 fixture 测试完全一致撰写新测试前请先阅读根目录 CONTRIBUTING.md 的 babel-plugin-x 章节。每个 fixture 是一个目录通常包含input.js/input.mjs待转换的输入代码options.json测试配置本质上就是一个.babelrc例如 test/fixtures/preset-options/useBuiltIns-false/options.json 指定presets: [[env, {...}]]output.js/output.mjs期望的转换结果可选exec.js需要实际执行断言时使用的执行脚本如 test/fixtures/plugins-integration/issue-15012/exec.js。fixture 目录的命名即测试名建议采用特性/场景-目标环境的可读命名例如 test/fixtures/bugfixes/safari-block-scoping-safari-10 或 test/fixtures/preset-options/ios-10。5.3 测试debug选项debug-fixtures 约定当改动涉及调试输出debug: true时打印到 stdout 的插件启用清单时需要专门的 debug 测试。流程如下在test/debug-fixtures目录下新建一个描述性命名的测试目录必须添加options.json与其他测试相同本质是一个.babelrc写入期望的测试配置添加stdout.txt内容为期望的 debug 输出。便捷之处在于如果目录中不存在stdout.txt测试运行器会自动为你生成一份——你只需检查生成的输出是否符合预期再将其纳入版本控制。当前仓库中实际对应此约定的样例可参考 test/fixtures/debug/browserslists-defaults/options.json{ validateLogs: true, ignoreOutput: true, presets: [ [ env, { debug: true, targets: { browsers: defaults } } ] ] }该目录同时保留了对应的stdout.txt期望输出与input.mjs测试时通过validateLogs: true严格校验 stdout 内容。这类 fixture 的目录命名也遵循描述性规则browserslists-defaults、shippedProposals-chrome-80、top-level-targets-shadowed等分别覆盖不同的调试场景。debug输出的实现入口在 src/debug.ts它负责将最终选定的插件与 polyfill 集合格式化为可读文本输出理解其输出格式有助于你写出精确匹配的stdout.txt。6. 贡献检查清单综合原文档与当前仓库实现提交一个新增特性支持的贡献前建议按以下清单自查特性状态确认该特性是否已进入正式 ES 版本而非 proposalproposal 走的是 src/shipped-proposals.ts 的登记流程两者入口不同。特性映射是否在 plugin-features.mjs 中按正确 ES 分块、正确顺序添加了插件与特性的映射注意exclude子特性与插件间依赖如transform-spread对 class/super 的依赖是否声明完整。兼容性数据是否已更新 download-compat-table.sh 的COMPAT_TABLE_COMMIT并运行npm run build-data重新生成 plugins.json确认无意外 diff。polyfill 归属built-in polyfill 数据是否按当前架构落入babel-plugin-polyfill-corejs3/core-js-compat而非已废弃的 preset-env 内useBuiltIns数据测试覆盖是否在 test/fixtures 下新增了输入/输出/配置齐备的 fixture若涉及调试输出是否在debug-fixtures下补充了options.json与stdout.txt或借助自动生成后人工核对7. 总结babel/preset-env的新特性支持本质上是一项数据工程plugin-features.mjs负责语义映射plugins.json负责引擎兼容版本download-compat-table.shnpm run build-data负责数据生成而 preset-env 运行时通过plugins-compat-data.ts与filter-items.ts完成最终筛选fixture/debug-fixtures 测试负责守住回归底线。理解这条管线后无论是贡献新特性还是排查某语法为何不被转换你都能快速定位到正确的数据文件与测试入口。建议动手前通读 packages/babel-preset-env/README.md 与根目录 CONTRIBUTING.md并参考 packages/babel-compat-data/README.md 了解 compat-data 包的发布边界。【免费下载链接】babel Babel is a compiler for writing next generation JavaScript.项目地址: https://gitcode.com/gh_mirrors/ba/babel创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表