跳至主内容

Babel 的现状

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

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

往期议题:Babel 路线图 #4130, 6.0 #2168

即使其他内容都不看,也请务必阅读社区生态部分。

本文也收录于Mariko Kosaka的2016年Web 开发者日历

发展历程

2014年9月,Sebastian创建了"6to5"。有趣的是,他开发这个项目是为了解决自己在理解编程语言及其工作原理时的痛点。你可能以为项目创建者早已精通编译器原理并完全掌握 JavaScript...但事实并非如此!阅读他的文章可以了解这段精彩故事:2015年回顾

6to5 的核心功能正是如此:将 ES6 代码轻松转换为 ES5 代码。当 6to5 更名为 Babel(如Not Born to Die所述)后,它蜕变为一个平台:一套旨在打造下一代 JavaScript 工具链的解决方案。它不仅支持 ES6 到 ES5 的编译,更允许开发者在其基础上构建工具。

以下是我们的一些重要里程碑:

  • 5.0.0版本中,通过引入stages阶段系统、添加.babelrc配置选项以及创建自定义转换的插件系统,Babel 更加贴合TC39 标准化流程

  • 6.0.0版本中,Babel 实现了模块化(这在当时颇具争议)。这项重大变革带来了可选功能(无默认配置)以及Presets预设和插件选项的概念。

    • 如他在文章所述,Sebastian 于2015年7月加入 Facebook,并在工作时间内完成了 Babel 6 的全部开发。
  • 6.3.13版本中,Sebastian 将我们的monorepo构建/发布工具抽离出来,形成了现在的Lerna。(有趣的是James重写了三次,而我不得不逐行审查)

    • 此后不久,Sebastian 和 James 都因 Babel 工作筋疲力尽,此时几位贡献者挺身而出。
    • 我们虽艰难寻找方向并处理蜂拥而至的缺陷/需求,但仍取得了丰硕成果!
  • 6.13.0 终于添加了预设选项

  • 6.14.0 添加了最新预设,该预设会随着每年更新的 JavaScript 规范保持同步。

  • 6.16.0 允许更换解析器或代码生成器。

  • 八月份,我们发布了基于 Babel 的代码压缩工具 Babili

  • 九月份,我们发布了babel-preset-env的首个版本(详见下文)。

  • Phabricator上运行一年后,我们回归到GitHub issues,这完全归功于@danez出色(却未被充分重视)的工作。

如果您在使用 Babel,请通过向我们提交PR用户页面告知我们!

如今babel-core月下载量超过 500 万次,总下载量近 6000 万次,被 Facebook/Netflix/Airbnb 等大型企业以及 React/Yarn 等开源项目采用。

感谢大家的持续支持!我们将继续作为 JavaScript 工具链的基石:编译、代码检查、代码压缩、代码重构(codemods)、代码覆盖率等。

当前状态

如果您有兴趣参与贡献,请查看下方链接的议题!

维护TC39 各阶段提案的 Babel 插件(从 Stage 0 开始)

TC39代表 Ecma 国际技术委员会第 39 分会:这是制定 JavaScript 标准的委员会。

Babel 采用TC39 的阶段体系对实验性插件进行分类。用户应能在TC39 流程 Stage 4规范被浏览器完全实现前轻松使用新特性。

Babel 在此过程中至关重要:开发者更新.babelrc文件比调整浏览器标志更简单,编写 Babel 插件比浏览器原生实现特性更快速——这正是 Babel 的核心价值。

但提案流程涉及大量迭代:语法可能变更甚至废弃。由于 TC39 每两月召开会议,插件至少应在每个阶段变更时更新,确保用户保持同步。

尽管建议谨慎使用 Stage 0/1/2 特性,但向提案负责人和委员会提供早期反馈极其宝贵。 虽然 Facebook 等公司会利用这类特性,但他们已创建代码重构工具(codemods)以便快速调整。


我们没有足够时间和资源维护每个插件,尤其在规范更新时。


接下来我们将与以下人员合作:

相关议题:

  • 我们是否应该在创建实际转换功能的同时,为第X阶段的提案创建代码修改工具(codemod)?

  • 私有字段

  • 装饰器提案

查看 thefeedbackloop.xyz 获取更多关于 TC39 的信息!

维护其他生态系统的插件:JSX/Flow

Babel 对 ReactFlow 生态系统至关重要,我们与 Facebook 的相关团队保持紧密合作。

相关议题标签:

babel-preset-env(Babel 的 "autoprefixer")

JavaScript 编译是个移动目标:规范每年更新,浏览器厂商持续跟进规范,用户可能放弃对早期浏览器的支持。乍看之下,似乎没有固定的编译目标标准。

该预设使用持续更新的 compat-table

这正是 babel-preset-env 的价值所在:它能根据指定环境自动确定需要使用的 Babel 插件。

其目标兼具使用简便性和输出高效性:您只需关注目标环境,即可利用原生代码优势,由预设自动决定所需插件。

配置示例

通过 browserslist 设定目标:Chrome 55 及其他浏览器的最近两个版本

JavaScript
{
"presets": [
["env", {
"targets": {
"chrome": 55,
"browsers": ["last 2 versions"]
}
}]
]
}

以当前 Node.js 版本为目标(使用 process.versions.node

JavaScript
{
"presets": [
["env", {
"targets": {
"node": "current"
}
}]
]
}

Chrome 55 useBuiltIns + webpack 2

JavaScript
{
"presets": [
["env", {
"targets": {
"chrome": 55
},
"modules": false,
"useBuiltIns": true
}]
]
}

输入

JavaScript
import "babel-polyfill";

输出(因环境而异)

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

相关议题:

通过 babel-eslint 进行代码检查

example of eslint

ESLint 在提案达到 Stage 4 之前不支持新的语言特性。因此我们维护了 babel-eslint(一个自定义的 ESLint 解析器),以便你能够继续对使用实验性语法的 JavaScript 代码进行检查。

这个项目是最难处理的项目之一:因为它只是 Babel 和 ESLint 之间的兼容层,当任一项目更新时,就需要不断进行更新,并且由于采用了 monkey-patching 方式,存在很高的意外变更风险。不幸的是,我们遇到了诸如 babel/babel-eslint#243babel/babel-eslint#267 这样的问题。

为此,我们希望通过改进与 ESLint 的作用域和遍历互操作性来减轻该项目的维护负担。甚至可能实现使用 Babel API 编写 ESLint 规则,反之亦然?

相关议题:

代码压缩

Babili 是我们新的基于 Babel 的代码压缩工具,让你能够生成针对最新浏览器优化的压缩代码。

输入

JavaScript
class Mangler {
constructor(program) {
this.program = program;
}
}
new Mangler();

输出

JavaScript
// ES2015 code -> Babili -> Minified ES2015 Code
class a{constructor(b){this.program=b}}new a;

更多信息请查看我们的博客文章

由于它最近才发布,我们正在寻找新的贡献者!对于想要参与新项目的人来说,这里有很多小错误和改进空间!

代码模式转换 / 重构 / eslint --fix

codemod 是一种工具辅助的代码修改;一种高级的查找替换操作。

如果你想将 merge({}) 改为 Object.assign({})(也许之后还会改为对象剩余属性),你可能会使用正则表达式替换。但你并不想替换代码中其他可能名为 merge 的部分,例如导入/导出、字符串、注释和局部变量。为了安全地进行替换,你需要更强大的工具,只更改你需要的特定代码。

尽管 Babel 已经能够将代码转换为其他代码,但作为编译器,它并不关心输入代码的样式。使用 Babel 的默认选项进行代码模式转换后,git diff 的结果会显得非常混乱。

引入 Recast:该工具能在保留未修改代码格式的同时,美化打印所有新增的 AST 节点。

recast

上图中,左上窗格是输入代码,右下窗格是运行 Babel 插件后的输出代码。此示例展示了工具在可能情况下保留输入代码空白符的能力。

通过在选项中传入 Recast,Babel 将为代码迁移工具提供强大支持。

.babelrc

JavaScript
{
"parserOpts": {
"parser": "recast"
},
"generatorOpts": {
"generator": "recast"
}
}

对源代码运行相关 Babel 转换并覆盖原文件:

Shell
babel src -d src

此功能刚刚实现,我们期待优化其易用性并探索其支持的各种转换场景。更多信息请参阅 6.16.0 版本博客

其他相关项目:JSCodeshiftjs-codemodLebab

相关议题:

代码覆盖率 / 插桩

我们将支持 nycbabel-plugin-istanbul 等工具。

插件生态系统

得益于活跃的社区,新插件层出不穷:无论是创新的 JSX 内联 CSS 方案,还是 测试重连 方案。

当前 npm 上有超过 1200 个 Babel 插件

关于如何发展和支持插件生态,我们进行了多轮深度讨论。试图监控所有仓库显然不切实际。

可考虑创建自动化机器人:编写针对 Babel 插件的专属规则/ESLint 规则、创建 API 变更的代码迁移脚本,并将插件集成到冒烟测试中。

  • 是否应创建新插件/实用插件通讯?

  • 如何普及插件开发知识?

  • 如何优化 ASTExplorer

文档(本网站!)

过去一年中文档贡献明显不足(参见 贡献者图谱)。

但近期我们取得了多项突破:

我们也新增了以下协作者:

  • @STRML:通过 #875 为所有 GitHub 页面添加了 Discourse 支持

  • @xtuc:通过 #990 添加了从 babel 仓库读取 README 的功能,无需再同步两份文档副本

  • @fredericmarx:通过 #998 为代码片段添加了复制到剪贴板的按钮支持

  • @seedofjoy:通过 #1003 为 REPL 添加了调整大小的功能

一些想法

  • 所有插件都应提供示例。也可嵌入 RunKit 或 REPL

  • 使用常见错误更新 FAQ

  • API 文档 / 改进 babel-handbook

相关议题:

未来规划

注意:以下所有内容都可能被更改或废弃。有些可能已在开发中,其余仅为需要正式讨论/负责人推进的建议

优先级应根据社区实际需求确定,而非仅因"有也不错"

插件 API 变更

插件/预设间的执行顺序存在大量混淆问题。这导致配置错误,迫使用户以非直观方式调整插件前后顺序

我们正讨论通过 API 变更减少这类困惑。但由于这是 Babel 核心的根本性改动,可能需要较长时间确定最佳方案

版本管理

自 Babel 6 起,我们通过 Lerna 采用固定版本管理模式。这使得所有变更的包能统一版本发布。其优势在于无需手动设置各包版本,所有组件同步更新。唯一例外是当某包存在破坏性变更时:所有包都将升级主版本号

这在 babel/notes 中有更详细的解释,但我们仍需为项目确定最佳的行动计划。

当我们需要将 Stage 0 规范更新到 Stage 1,且这会对解析器造成破坏性变更时,会发生什么?我们是直接升级主版本号,还是等待批量处理变更,或者通过插件的多个版本来实现?

讨论议题

改变对 Stage X 预设的认知

相关议题:

速度

性能本身就是一项特性!虽然有时其他事项(错误修复、规范合规性等)更优先,但在以下几个方面仍然至关重要:

  • 如何减少安装大小/时间,特别是多包项目?(yarn 对此有帮助)

  • 如何提升解析速度?

  • 如何开发更快的插件(并单独测量其性能)?

  • 如何更快生成转换后的代码?

  • 如何生成在浏览器中运行更快的代码(https://fhinkel.github.io/six-speed/)?

如果您在阅读编译输出时发现问题,请报告并寻求帮助提交 PR!

先前议题:

可能的 TypeScript 支持?

Babel 是否可以学习解析 TypeScript 语法(类似 Flow 的处理方式)?我们可以添加插件来剥离 TypeScript 类型以提升互操作性。

这意味着需要解析 TypeScript 特有语法并移除类型。但 TypeScript 包含非类型语法(如 enum),这类内容需要进一步讨论。

利用类型信息?

集成 Flow/TypeScript 等类型系统进行优化,使 Babel 能通过这些工具判断标识符(如 arr)是否确认为 Array 类型。

已有插件实现类型检查:babel-plugin-typecheckbabel-plugin-tcomb

接收依赖图/多文件操作?

这将更好地与 Webpack 等工具集成,实现跨文件转换或全代码库优化。主要应用场景包括:压缩工具(根据全应用使用情况移除属性)、检测导入/导出缺失或无效的错误。

解析器错误

提供更友好的解析器错误提示,类似面向人类的编译器错误

显然,我们都希望看到有用的错误提示!

我们可以优化推断/猜测用户意图的能力,避免模糊的错误提示。欢迎反馈您遇到的此类情况!

相关议题:

babel-init

本质上是简化 Babel 的初始配置流程,类似 create-react-app 的做法。

  • 通过问答式引导创建初始化的 .babelrc 文件

可能的实现思路:

  • 询问目标环境(浏览器/node)并传递给 babel-preset-env

  • 询问是否启用实验性特性(添加特定插件)

  • 重新激活 babel npm 包的功能:使其回归类似 Babel 5 的默认/开箱即用配置模式的 babel。可默认启用 env 预设并指定为 latest 2 browsers(无需额外配置)。

相关议题:

运行 tc39/test262

test262 用于测试对 tc39.github.io/ecma262 持续维护的未来 ECMAScript 标准草案的符合性,同时包含所有 Stage 3 及更高阶段的 TC39 提案。该项目由 Tom Care (@tcare) 维护,并得到 ECMAScript 社区的广泛贡献。

通过官方规范测试套件验证 Babel 可确保符合标准规范,或至少能及时发现偏差。需建立过滤机制排除无法编译的特性(如 proxy、TCO 等),并搭建便捷流程来检查失败用例、提交问题报告和修复方案。

相关议题:

冒烟/集成测试

可考虑实现反向 Greenkeeper 机制,或在 Babel 的 master 分支上运行测试,从而在发布前捕获重大回归问题(Node.js 的 citgm 项目即采用此理念)。理论上应选取使用 Babel 的大型开源项目运行其测试套件。

motiz88/babel-smoke-tests 是个良好起点!若已有类似解决方案也欢迎推荐!

程序分析

Alan Shreve (@inconshreveable) 的演讲 "理想化提交日志:通过程序切片简化代码" 极具启发性,促使 @kentcdodds 尝试通过 slice-js 在 JavaScript 中实现该技术。

核心思路是:虽然我们拥有大量辅助编写代码的工具,但理解/阅读代码的工具却很少。你可以将代码切片视为一种针对性的死代码消除技术。

代码切片示例

程序切片本质上会从源代码中剔除未被测试用例使用的代码。如果存在大量在当前用例中未执行的 if 语句和循环,它们就不会出现在程序切片中。

  • 语义化(基于 AST 的)Grep 工具?

类似 graspjs 的思路,我认为基于 AST 进行查找替换会非常有趣。这将使我们能够创建更多分析工具:比如查找所有立即执行函数(IIFE)、统计方法调用次数,甚至分析代码库中的类数量。

babel --settings

该命令将打印所有信息(包括报错时),同时提供各插件执行时间的性能指标。

解析器统一

TheLarkInn/js-parser-discussions 和早期的 ESTree 项目中,已有关于解析器/AST 统一化的讨论。

遗憾的是在 Babel 6 中,我们出现了"分叉"现象——Babel 的 AST 与 ESTree 存在若干差异。Babel 旨在支持 stage x 特性,而其他解析器可能仅支持 stage 4 特性。在规范合规性、性能、阶段特性支持、错误提示、扩展性和发布策略等方面,不同项目各有侧重。但我们应该对破坏性变更保持开放态度,以促进更好的互操作性和社区发展。

与 Sweet.js 的互操作性?

参考先前 issue。或许我们可以专注于实现更好的互操作性方案?

Node.js 支持策略

是否应该根据 Node.js 版本的 EOL(生命周期结束)来终止支持?通常我们应该等待多久才执行此操作?

  • 我们是否应该继续支持尚未升级的用户?

  • 某些转换/PR 因此受阻,因为相关工具已放弃对旧版本的支持

  • 许多构建时工具(如 ESLint)已采取此策略

  • 我们应该为此单独发布主版本,还是结合其他变更共同规划?

  • 讨论 Issue

Babel 5 到 6 的迁移/升级路径

社区升级到 Babel 6 的过程异常艰难。初始版本发布较为仓促。尽管我们发布了 6.0 版本公告、后续的 配置指南,甚至推出了 迁移辅助工具(现已弃用),用户仍难以理解这些变更。

目前仍有大量用户在使用 Babel 5,我们不愿抛弃这些用户。我们能做些什么来帮助他们升级?未来需要采取哪些措施来确保 Babel 7 不会重蹈覆辙?还有哪些项目/社区值得我们联系并提供帮助?

相关议题:

其他建议

还有哪些未被提及的想法?请通过推特 @babeljs 联系我们,在 Slack 留言(加入地址:https://slack.babeljs.io/),在本文下方评论,或在仓库中创建讨论议题!

还有哪些项目或社区值得我们深入合作?如何优化贡献者体验?如何让开发流程更加透明?

社区

历史议题:

你或许认为随着项目使用量增长,会有更多人参与维护。但和多数无企业支持的开源项目一样,我们持续面临维护和可持续性挑战:开发者会精疲力竭、转向新项目或忙于工作/家庭事务。

正如 James 在《致 JavaScript 社区》所述,当前 Babel 团队规模较小。

Babel 不是企业产品,不是 Facebook 的特设团队,也非企业资助的开源项目。它是由社区驱动、仅靠少数人支撑的项目,我们期待更多人加入壮大。

如果你有意为你使用的工具贡献力量,我们期待你的加入!

如何参与贡献?

我们多数项目都标注了 beginner-friendly(新手友好)和 help-wanted(需要帮助)标签,也可关注 discussion(讨论)类议题。

核心团队

当前核心成员:

近三月新增协作者:

Babili 核心团队:

如上所述,我们有许多网站贡献者:

虽不活跃但仍可提供帮助的成员:

如何联系团队?

GitHub

要报告错误或提交拉取请求(PR),请查看我们的代码仓库

Twitter

您可以通过 @babeljs 在 Twitter 上联系我们,或直接@团队成员。

我本人加入 Twitter 就是为了能与用户交流并提供帮助。发布新功能和更新日志非常实用,这有助于我们获得反馈!

Slack

我们在 Slack 上拥有相当活跃的社区!

您会发现许多乐于助人的优秀社区成员,例如 Jordan Harband, @ljharbJessica Franco, @JessidhiaJimmy Jia, @taionDenis Pushkarev, @zloirock 等!

若您有疑问,请加入 #discussion 频道;若想参与贡献或了解开发进展,请查看 #development 频道。

我们尽量避免不必要的私下讨论:我本人通常会将正在处理的问题/PR 公开分享,供大家评审讨论。

其他方式

我们还能如何与社区互动?是否应该组织线下聚会、参加技术会议或举办黑客松?

如何实现 Babel 的可持续发展?是否应设立 Open Collective 或寻求基金会支持?是否需要聘请项目经理

请告诉我们您的想法!您对 Babel 有哪些期待?


发现拼写错误或问题?请提交 PR 或在 babel/babel.github.io#1014 留言

我们想借此机会说明:团队中许多人参与Babel的初衷是为了学习JavaScript,而非因为已是专家才来贡献。就我个人而言,接触这个项目时对编译器一无所知,ES6也是刚接触的概念。能走到今天,全因一丝好奇心和众多伙伴的鼓励。我希望能延续这份精神,期待我们共同成长进步。

衷心感谢您的阅读!

朱亨利 (@hzoo) (@left_pad)

特别鸣谢以下伙伴的审阅与宝贵建议:@DrewML, @mrjoelkemp, @kentcdodds, @existentialism, @jdalton, @gaearon, @nolanlawson, @jayphelps, @montogeek, @TheLarkInn, @jasonLaster, @benjamn, @addyosmani, @Daniel15, @loganfsmyth, @gr2m, @mathiasbynens, @chicoxyzzy, @bvaughn, @bcoe.