Skip to main content

Babel 路线图

本文档概述了我们的团队成员希望在今年进行的一些改进。

这远不是我们将为 Babel 带来的所有新功能或重要更改的完整列表,但是,如果你对项目发展的大方向感兴趣,那么这是一个很好的总结。实际上,我们也许并不能完成列出的所有要点,甚至可能会将某些实现推迟到明年。某些要点已有明确的起止时间,而另一些则需要更多的研究或 RFCs

如果贵公司有兴趣并希望直接赞助,请 联系我们

Babel 2021 路线图

Babel 8

We have been talking about the Babel 8 release for more than one year (we initially scheduled it about one year ago)! However, we are now closer then ever to its release!

剩下的大部分工作都是在 跟踪 issue,但仍有一些阻塞内容:

  • 我们希望取消对 Node.js 10 的支持,它将在 2021-04-30 停止维护。
  • 我们希望将 Babel 作为一个纯 ES 模块包发布。现在我们正在转换我们的源码以兼容 Node.js 的 ES 模块实现,同时,我们正在研究如何让目前使用 Babel 的人更容易地将 ES 模块编译成 CommonJS 模块。
  • 我们正在尝试将我们的 TypeScript AST 项目与 typescript-eslint 项目对齐。它们的 AST 几乎 完全相同,但我们还需要做出一些小的突破性更改,才能完全一致。
  • 我们的发布基础设施还不支持预发布,也不支持使用多个 "main" 分支(一个用于 Babel 8,一个用于 Babel 7)。
  • 我们还没有弄清楚 Babel 7 的维护策略。

实现新的 TC39 提案

除了顶级 await、导入断言和 JSON 模块(它们最好由使用依赖关系图的构建工具来处理)之外,Babel 目前可以解析并转译所有第 3 阶段提案。

我们支持所有第 2 阶段提案,除了:

  • 新版装饰器提案(我们需要同时实现解析和转译);
  • 转译块级模块提案(在 Babel 7.13.0 我们实现了解析)。

我们将实现对装饰器的支持,并研究是否应该以及如何实现对块级模块的转译。

尽管我们不支持许多第 1 阶段提案,但最近对管道运算符和 do 表达式进行了更新。因为我们已经支持这些提案,并且社区也对它们非常期待,所以我们将继续更新我们的实现。

还有其它提案(比如模式匹配)我们至今没有实现,因为它们的拥护者希望对语法和语义进行重大更改。不过,我们正在密切关注它们的发展,一旦它们稳定下来,我们就会在 Babel 中实现它们。

@babel/preset-env 移入 @babel/core

一个最小的 Babel 转译配置至少需要三个包:

  • @babel/core
  • @babel/preset-env
  • 一个 Babel "运行器"(@babel/clibabel-loader@rollup/plugin-babel 等)

@babel/preset-env 直接移入 @babel/core 有两大好处:

  • 在简单的项目中配置 Babel 将会更容易,你只需要在 babel.config.json 中启用 compileJS: true 选项(或者在将来它甚至可能是默认值 —— 目前它不能作为默认值是因为 @babel/eslint-parser 不编译源码)
  • 它将确保插件版本与 @babel/core 版本保持同步,从而避免因为 不匹配/不兼容 的包版本而导致的大多数问题
  • 当我们迁移至 ES 模块时,将很难在 transformSync 中同步解析和加载插件。而这就可以解决前面的问题。

已经有一个 RFC 可以为 @babel/core 中的标准 ECMAScript 特性迁移 插件,这是朝该方向迈出的第一步。

使用我们当前的 @babel/preset-env 架构,我们需要专门处理官方插件,以便根据 targets 自动启用或禁用它们。 然而,这有两个缺点:

  • 特定插件的兼容性数据与插件实现完全分离(它甚至不是依赖,更像是内部隐式的对等依赖:插件 -> @babel/core -> @babel/compat-data);
  • 官方插件将从 @babel/core 获得特殊对待,但我们希望确保第三方插件具有与官方插件相同的能力。

继续开发 babel-polyfills 项目

我们已经决定从 Babel 8 的 @babel/preset-env 中移除较旧的 core-js@2 的支持。我们还希望停止推广特定的第三方 polyfill,因为这可能会给我们的用户留下这样的印象:它是 Babel 本身的一部分。

这可能以两种不同的方式进行:

  • 我们只需从 Babel 8 的 @babel/preset-env 中移除 core-js@3,鼓励用户迁移到 babel-plugin-polyfill-corejs3(从 v7.10.0 开始,在 @babel/preset-env 内部使用)
  • 我们可以在 @babel/preset-env 中保留对 core-js@3 的支持,但在移动转译插件时,不将其迁移到 @babel/core

无论我们采取哪种方式,当我们的用户需要在他们的配置中更新 core-js 集成的时候,我们希望为他们提供至少一个替代方案。core-js 是一个非常好的 polyfill,它确保了尽可能高的规范合规性,但用户可能更喜欢不同的权衡。

(Nicolò) is working with @ljharb to make sure that the @es-shims project supports at least all the ES2015+ features (we actually aim for ES5+), so that Babel users are free to choose between at least two options.

这需要在放弃对 core-js@3 的内置支持 之前 完成, 这样对 es-shims 感兴趣的人就不需要迁移两次了。

扩展粒度转译的 targets 使用率

从一开始,@babel/preset-env 就使用 targets 选项自动启用或禁用转译插件。

然而,在 Babel 插件与浏览器中实现的特性之间不存在一对一的映射。

例如,对于不同的类字段类型(公共和私有、静态和实例),我们只有一个插件,但浏览器却有不同的兼容性矩阵:

  • Firefox 73 和 Safari 14 仅支持公共实例字段
  • Firefox 75+ 支持公有实例和静态字段
  • Chrome 79+ 支持公有和私有字段,但不支持某些可选链接表达式中的私有字段
  • Chrome 84+ 完全支持私有字段,以及私有方法
  • Safari TP 121 完全支持私有字段(即使使用 ?.),但不支持私有方法

为每个功能创建一个插件并不是最优的。例如,我们可以将私有方法转译为私有字段,然后根据需要将它们转译为较旧的语法。但是,如果我们知道私有方法需要向下转译,我们可以通过直接将私有方法向下转译为较旧的语法来生成更好/优化的输出,而不需要中间步骤。

从 Babel 7.13.0 开始,我们可以直接在插件中读取 targets 选项,我们可以修改我们的插件来自动执行给定 ECMAScript 特性的 部分 编译,这将在输出大小和运行时性能方面带来优势。

现有技术

这种方法并不是全新的。多亏了与 @_developit 的合作,在 Babel 7.9.0 中,我们在 @babel/preset-env 中引入了一个新的 bugfixes: true 选项。启用此选项并使用 esmodules: true 作为编译目标时,我们只会部分编译 某些特性。这就是我们最初考虑这种可能性的原因,但当前的部分转译在使用更现代的目标(例如:defaults, not ie 11)时用处不大。

我们已经使用 targets 选项来决定在编译对象扩展时是否可以使用 Object.assign

行动要点

这个目标可以分为两个可以并行完成的大任务:

  • 我们需要通过收集真实的 browserslist 查询并模拟流行的查询(例如:defaults>2%, not dead)在未来将如何演变,来确定这些优化在 哪些方面 有用。
  • 我们需要实际实现必要的优化,确保它们仍然可以与其他插件很好地协同工作(因为它们会极大地增加可能的转译组合数量)。

调查新的编译器 assumptions

在 Babel 7.13.0 中,我们引入了一个新的顶层 assumptions 选项来正式化 loose 模式选项的功能,并为我们的用户提供更精细的控制(因为他们通常只能启用 某些 假设,而不是所有)。

但是,我们只包含了在 loose 模式下编译时 已经 做出的假设选项。我们现在可以审查我们的用户可能需要哪些新的假设。

There are already some proposals, such as:

  • #8222 - assume that all the ESM imports are actually immutable, avoiding the code needed for live bindings.
  • #11356 - assume that compiled classes do not extends native classes, avoiding the runtime performance cost needed to instantiate possibly native classes.

We can find which new assumptions we should implement, by:

  • Manually checking which features we compile to "non-obvious" output, which is usually caused by edge cases that many developers don't care about.
  • Asking for feedback from the community, since developers can test which assumptions work and which don't on their applications.

检修 Babel REPL

Babel REPL 是一个方便学习 Babel 如何转译源码的 playground。

目前的限制:

已有的优秀功能:

  • AST 资源管理器(与现有系统集成)
  • 具有完整堆栈跟踪的标准错误输出作为错误日志
  • 标准输出作为输出
  • 从 UI 更改 Babel 版本

Babel 站点仓库上至少有 15% 的未解决 issues 与 REPL 有关:https://github.com/babel/website/issues?q=is%3Aissue+is%3Aopen+label%3Arepl

教育/调试工具

与 REPL/AST 资源管理器相关,我们可以使用更多工具来帮助我们自己和第三方插件进行通用插件开发。这在本质上是相当具有探索性的:AST 本身、调试等有不同的可视化。

一些事情已经在进行中,Henry 一直在断断续续地工作:

  • Codesandbox for making a simple Babel plugin in the same vein as https://astexplorer.net but with custom configs.
  • Visualization of input to output mapping to help understand how Babel transforms its code. Could be useful even for documentation in getting JavaScript users familiar with new syntax or a specific demo of a transform.
  • Mapping of input to output like a sourcemap type structure. Can do a reverse mapping to find out what plugin caused the code to be outputted a certain way which helps with debugging.

查看我们正在思考的互动示例:https://babel-explorer.netlify.app/(在底部扇区单击并按住鼠标!)