跳至主内容

即将发布 7.0 版本

· 1 分钟阅读
非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

请查看 7.0 版本规划 了解 7.0 预发布阶段的最新动态。如果本文有任何不清楚之处,请随时告知!

项目动态

  • 我们新增了 视频专区!这个页面专为希望深入了解 Babel 工作原理、并愿意帮助他人贡献的开发者设计。这里汇集了团队成员和社区开发者关于 Babel 及相关技术的会议演讲视频(如果您也做过类似分享,欢迎提交 PR 添加)。

视频

  • 我们还创建了全新的 团队页面!后续将更新更多成员的工作内容和参与原因。对于如此规模的项目,参与贡献的方式多种多样。

团队

  • Babel 在 2017 年 9 月 28 日 迎来了三周岁生日!

  • Daniel 已将 babel/babylonbabel/babel-preset-env 迁移 至主仓库 babel/babel,包含完整的 git 历史记录、标签和 issue。

  • 我们收到了 Facebook 开源项目的 $1k/月 捐款

    • 这是项目启动以来的最高月度捐赠(次高为 $100/月)
    • 当前资金将用于线下会议和派遣成员参加 TC39 会议(该会议每两月在全球不同地区举办)
    • 若有企业希望专项赞助,我们可以创建独立 issue 跟踪。此前因需自付费用或依赖同期会议报销,专项赞助难以实现

您能如何助力!

如果贵公司希望通过支持 JavaScript 生态的核心基础设施来 回馈社区,请考虑向我们的 Open Collective 捐款,或捐赠开发者时间参与项目维护。

#1 参与项目维护(贡献工作时间)

面对庞大的工作量与责任压力,我们最需要的是长期投入的贡献者。正如我成为维护者时的感受,起初我也自觉准备不足,但整个团队目前仅有少数成员在支撑。

#2 资金支持开发

我们亟需资金支持团队成员全职投入。例如 Logan 已离职,目前正用项目资金兼职投入 Babel 开发!

#3 其他创意贡献 😊

比如 Angus 为我们创作了 官方主题曲

升级指南

我们还将开发一个升级工具,帮助重写 package.json/.babelrc 文件等。理想情况下,这意味着它将自动修改必要的版本号变更、包重命名和配置更改。

请踊跃提供帮助并在尝试更新时提交问题!这是参与项目并帮助生态系统升级的绝佳机会!

之前的文章总结

  • 放弃对 Node 0.10/0.12/5 的支持

  • 更新了 TC39 提案

    • 数字分隔符:1_000
    • 可选链操作符:a?.b
    • import.meta(可解析)
    • 可选的 catch 绑定:try { a } catch {}
    • BigInt(可解析):2n
    • 将导出扩展拆分为 export-default-fromexport-ns-form
  • 支持 .babelrc.js(使用 JavaScript 替代 JSON 的配置文件)

  • 新增 TypeScript 预设 + 分离 React/Flow 预设

  • 移除了内部 babel-runtime 依赖以减小体积

最新更新的 TC39 提案

  • 管道操作符:a |> b

  • Throw 表达式:() => throw 'hi'

  • 空值合并操作符:a ?? b

已弃用的年度预设(例如 babel-preset-es20xx)

简而言之:请使用 babel-preset-env

有什么比自己决定使用哪个 Babel 预设更好?让它自动为你完成!

尽管维护这些数据列表的工作量巨大——这正是我们需要帮助的原因——但它解决了多个问题:确保用户与规范同步、减少配置/包混淆、简化升级路径、减少功能混淆问题

babel-preset-env 实际上是个相当古老的预设,它替代了你需要的所有其他语法预设(es2015、es2016、es2017、es20xx、latest 等)

npm 预设

它能编译 JavaScript 的最新年度发布(所有 Stage 4 特性),替代了所有旧预设。同时还能根据你指定的目标环境进行编译:无论是针对最新浏览器的开发模式,还是针对多版本构建(例如为 IE 和常青浏览器分别构建)

暂不删除 Stage 预设(babel-preset-stage-x)

编辑:我们已移除它们,此处有详细说明

我们始终能保持其更新,也许只需要确定比当前预设更好的替代方案

目前,stage 预设本质上只是我们在 TC39 会议后手动更新的插件列表。为了使其可管理,我们需要允许这些"不稳定"包进行主版本升级。部分原因在于社区无论如何都会重新创建这些包,因此我们不妨通过官方包来实现,从而能够提供更好的消息通知等支持。

重命名:作用域包 (@babel/x)

以下是我近一年前进行的投票:

当时使用作用域包的项目不多,大多数人甚至不知道它们的存在。那时可能需要付费购买 npm 组织账户,而现在是免费的(也支持非作用域包)。作用域包的搜索问题已解决,下载计数功能正常运作。唯一遗留问题是某些第三方注册表仍不支持作用域包,我认为现在继续等待这种情况改善已显得不太合理。

若需了解我们倾向使用作用域包的原因:

  • 命名更简单:无需检查是否有人使用相同命名规则创建了插件

  • 避免包抢占问题:

    • 有时用户因有趣而创建 babel-preset-20xx 等包,我们需发 issue 或邮件索回
    • 存在合法包恰好与我们计划名称冲突  - 当新提案(如可选链、管道运算符)即将合并时,有人抢先分叉并以相同名称发布。导致我们发布时提示包名已被占用 🤔,不得不联系对方和 npm 支持团队取回包名
  • 明确区分官方包与社区包:用户可能因名称混淆误用非官方包。例如曾有报告称 babel-env 重写其 .babelrc 文件,耗费多时才意识到并非官方 babel-preset-env

因此使用作用域包显然是合理选择,甚至我们应该更早实施 🙂!

作用域包更名示例:

  • babel-cli@babel/cli

  • babel-core@babel/core

  • babel-preset-env@babel/preset-env

重命名:-proposal- 标识

所有提案相关包现均包含 -proposal- 标识,表明其尚未正式纳入 JavaScript 规范

因此 @babel/plugin-transform-class-properties 更名为 @babel/plugin-proposal-class-properties,一旦进入 Stage 4 我们会将其名称改回

重命名:移除插件名称中的年份

早期插件名称包含年份,但现阶段已无必要保留

因此 @babel/plugin-transform-es2015-classes 简化为 @babel/plugin-transform-classes

由于仅 es3/es2015 系列包含年份,es2016 或 es2017 的命名保持不变。不过我们正用 preset-env 逐步取代这些预设,对于模板字面量修订提案,为简化直接将其合并至模板字面量转换插件

对等依赖与集成

我们正在为所有插件 (@babel/plugin-class-properties)、预设 (@babel/preset-env) 和顶层包 (@babel/cli, babel-loader) 引入对 @babel/core 的对等依赖

peerDependencies 是预期会被你的代码使用的依赖项,与仅作为实现细节的依赖项不同。 — Stijn de Witt via StackOverflow

babel-loader 原本就对 babel-core 设置了 peerDependency,现在只需将其改为 @babel/core。这样可防止用户安装错误版本的 Babel 包。

对于已设置 babel-core 作为 peerDependency 且尚未准备好重大版本更新的工具(因为变更 peerDependency 属于破坏性更新),我们发布了 babel-core 的一个新版本 babel-core@7.0.0-bridge.0 作为过渡方案。更多细节请参考此 issue

类似地,gulp-babelrollup-plugin-babel 等包原先依赖 babel-core。现在这些包将改为对 @babel/core 设置 peerDependency。这样当 @babel/core 的 API 未变更时,这些包无需进行主版本升级。

#5224 实验性包的独立发布机制

我在 Babel 现状报告Versioning 章节提到过此机制。GitHub Issue

你可能还记得,在 Babel 6 之后,Babel 演变成了一组 npm 包,形成了自己的自定义预设(preset)和插件(plugin)生态系统。

但此后我们始终采用"固定/同步"的版本控制(所有包版本均低于 v7.0)。当我们发布新版本如 v6.23.0 时,仅包含源码更新的包会发布新版本,其余包保持不变。由于我们使用 ^ 版本标识符,这套机制基本可行。

但该机制存在缺陷:当单个包需要主版本升级时,所有包都必须同步升级。这导致我们要么频繁发布小规模破坏性更新(不必要),要么将大量破坏性变更堆积到单次发布。因此我们希望区分实验性包(Stage 0 等)与其他包(如 es2015)。

这意味着当规范变更时,我们将对任何实验性提案插件进行主版本升级,而无需等待整个 Babel 更新。任何处于 Stage 4 以下的提案都可能通过主版本升级引入破坏性变更,Stage 预设本身也适用此规则(如果我们不完全弃用它们)。

这与我们变更 TC39 提案插件命名(使用 -proposal- 前缀)的决策一致。若规范变更,我们将对插件及其所属预设进行主版本升级(而非仅发布可能造成破坏的补丁版本)。随后需弃用旧版本并建立自动更新机制,确保用户始终跟进最新规范(避免类似装饰器方案的遗留问题)。

.babelrc 中的 env 选项不会被弃用!

前文不同,我们修复了合并行为使其更一致

env 中的配置优先级高于根配置项,且不再采用同时使用两者的怪异方式。现在插件和预设会根据自身标识进行合并,因此你可以:

JavaScript
{
presets: [
['env', { modules: false}],
],
env: {
test: {
presets: [
'env'
],
}
},
}

当设置 BABEL_ENV=test 时,将用测试环境的配置(不含选项)替换根环境配置。

支持 class A extends Array(历史遗留问题)

Babel 将自动封装所有原生内置对象(如 ArrayErrorHTMLElement 等),确保在编译类语法时能正确支持继承。

性能优化

preset-env: "useBuiltins": "usage"

babel-preset-env 不仅能根据目标环境编译语法,通过 useBuiltIns 选项还能按需添加目标环境不支持的 polyfill。

启用该选项后,如下代码:

JavaScript
import "babel-polyfill";

能够转换成

JavaScript
import "core-js/modules/es7.string.pad-start";
import "core-js/modules/es7.string.pad-end";
// ...

如果目标环境恰好支持除 padStartpadEnd 之外的其他 polyfill。

然而,为了更进一步优化,我们应该只导入代码库中实际"使用"的 polyfill。如果代码中根本没用到 padStart,那为什么要导入它呢?

"useBuiltins": "usage" 是我们实现按需加载的首个方案。它会在每个文件顶部动态导入 polyfill,但仅当检测到代码中实际使用时才导入。这种方式可确保应用仅加载必要的最小 polyfill 集合(且仅在目标环境不支持时才加载)。

例如代码中使用 Promise 时,若目标环境不支持,则会在文件顶部导入其 polyfill。打包工具会对相同模块进行去重,因此不会导致重复导入。

JavaScript
import "core-js/modules/es6.promise";
var a = new Promise();
JavaScript
import "core-js/modules/es7.array.includes";
[].includes
a.includes

通过类型推断,我们可以判断 .includes 是否为数组方法。当前逻辑可能存在误判,但相比全量导入 polyfill 仍是更优方案,后续将持续优化。

其他更新

  • babel-template 速度更快且更易用

  • regenerator 改用 MIT 许可证(该依赖用于编译生成器/异步函数)

  • modules-commonjs 插件新增 "lazy" 选项 #6952

  • 现可在 .babelrc 中使用 envName: "something" 或通过 CLI 传递 babel --envName=something,无需依赖 process.env.BABEL_ENVprocess.env.NODE_ENV

  • 新增 ["transform-for-of", { "assumeArray": true }] 配置,将所有 for-of 循环编译为常规数组遍历

  • preset-env 的 loose 模式默认排除 transform-typeof-symbol #6831

  • 改进语法错误的报错信息

正式版发布前待办事项

  • 实现 .babelrc 查找机制(需在首个 RC 版前完成)

  • 支持 "overrides" 配置:基于 glob 模式应用不同配置

  • 在 babel-core 中实现缓存及失效逻辑

  • 实现或制定独立于 helper 的 polyfill 版本管理方案,确保不强制绑定 core-js 2 或 3,因为用户项目可能依赖特定版本且通常不希望同时加载两者。

  • 完成可运行的装饰器实现,或提供功能完整的旧版实现,并明确在 7.x 周期内落地当前规范行为的路径。

致谢

特别感谢志愿者团队:Logan 全力修复配置系统等核心问题并承担繁重工作;Brian 接手 preset-env 维护及我先前的工作 😛;Daniel 在需要时总挺身而出,无论是维护 babel-loader 还是协助迁移 babylon/babel-preset-env 仓库。同样感谢 NicoloSvenArtemJessica 过去一年的大力支持。

我十分期待这次发布(也实在疲惫,毕竟耗时近一年 😝),但也不愿仓促行事。这个版本周期充满波折,但我收获颇丰,相信团队其他成员也是如此。

若说今年真正学到什么,那就是应该践行而非空谈这些感悟。

同时感谢 Mariko温柔督促让我最终完成本文(历时两个月)