即将发布 7.0 版本
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
请查看 7.0 版本规划 了解 7.0 预发布阶段的最新动态。如果本文有任何不清楚之处,请随时告知!
项目动态
- 我们新增了 视频专区!这个页面专为希望深入了解 Babel 工作原理、并愿意帮助他人贡献的开发者设计。这里汇集了团队成员和社区开发者关于 Babel 及相关技术的会议演讲视频(如果您也做过类似分享,欢迎提交 PR 添加)。
- 我们还创建了全新的 团队页面!后续将更新更多成员的工作内容和参与原因。对于如此规模的项目,参与贡献的方式多种多样。
-
Babel 在 2017 年 9 月 28 日 迎来了三周岁生日!
-
Daniel 已将
babel/babylon和babel/babel-preset-env迁移 至主仓库 babel/babel,包含完整的 git 历史记录、标签和 issue。 -
我们收到了 Facebook 开源项目的 $1k/月 捐款!
- 这是项目启动以来的最高月度捐赠(次高为 $100/月)
- 当前资金将用于线下会议和派遣成员参加 TC39 会议(该会议每两月在全球不同地区举办)
- 若有企业希望专项赞助,我们可以创建独立 issue 跟踪。此前因需自付费用或依赖同期会议报销,专项赞助难以实现
您能如何助力!
如果贵公司希望通过支持 JavaScript 生态的核心基础设施来 回馈社区,请考虑向我们的 Open Collective 捐款,或捐赠开发者时间参与项目维护。
#1 参与项目维护(贡献工作时间)
Engineer: There's a thing in SQL Server Enterprise blocking us
— Shiya (@ShiyaLuo) November 16, 2017
Company: Let's set up a call next week with them an ongoing discussion to resolve it next quarter
Engineer: There's a thing we need in babel, can I spent 2 days with a PR for it
Company: lol no it's their job https://t.co/icgaoJ0dTe
面对庞大的工作量与责任压力,我们最需要的是长期投入的贡献者。正如我成为维护者时的感受,起初我也自觉准备不足,但整个团队目前仅有少数成员在支撑。
#2 资金支持开发
Company: "We'd like to use SQL Server Enterprise"
— Adam Rackis (@AdamRackis) November 16, 2017
MS: "That'll be a quarter million dollars + $20K/month"
Company: "Ok!"
...
Company: "We'd like to use Babel"
Babel: "Ok! npm i babel --save"
Company: "Cool"
Babel: "Would you like to help contribute financially?"
Company: "lol no"
我们亟需资金支持团队成员全职投入。例如 Logan 已离职,目前正用项目资金兼职投入 Babel 开发!
#3 其他创意贡献 😊
升级指南
我们还将开发一个升级工具,帮助重写 package.json/.babelrc 文件等。理想情况下,这意味着它将自动修改必要的版本号变更、包重命名和配置更改。
请踊跃提供帮助并在尝试更新时提交问题!这是参与项目并帮助生态系统升级的绝佳机会!
之前的文章总结
-
放弃对 Node 0.10/0.12/5 的支持
-
更新了 TC39 提案
- 数字分隔符:
1_000 - 可选链操作符:
a?.b import.meta(可解析)- 可选的 catch 绑定:
try { a } catch {} - BigInt(可解析):
2n - 将导出扩展拆分为
export-default-from和export-ns-form
- 数字分隔符:
-
支持
.babelrc.js(使用 JavaScript 替代 JSON 的配置文件) -
新增 TypeScript 预设 + 分离 React/Flow 预设
- 新增 JSX Fragment 支持及多项 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 等)
它能编译 JavaScript 的最新年度发布(所有 Stage 4 特性),替代了所有旧预设。同时还能根据你指定的目标环境进行编译:无论是针对最新浏览器的开发模式,还是针对多版本构建(例如为 IE 和常青浏览器分别构建)
暂不删除 Stage 预设(babel-preset-stage-x)
编辑:我们已移除它们,此处有详细说明
Frustration level if we remove the Stage presets in Babel? (in favor explicitly requiring proposal plugins since they aren't JavaScript yet)
— Henry Zhu (@left_pad) June 9, 2017
我们始终能保持其更新,也许只需要确定比当前预设更好的替代方案
目前,stage 预设本质上只是我们在 TC39 会议后手动更新的插件列表。为了使其可管理,我们需要允许这些"不稳定"包进行主版本升级。部分原因在于社区无论如何都会重新创建这些包,因此我们不妨通过官方包来实现,从而能够提供更好的消息通知等支持。
重命名:作用域包 (@babel/x)
以下是我近一年前进行的投票:
Thoughts on @babeljs using npm scoped packages for 7.0?
— Henry Zhu (@left_pad) January 18, 2017
当时使用作用域包的项目不多,大多数人甚至不知道它们的存在。那时可能需要付费购买 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-babel、rollup-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 中的配置优先级高于根配置项,且不再采用同时使用两者的怪异方式。现在插件和预设会根据自身标识进行合并,因此你可以:
{
presets: [
['env', { modules: false}],
],
env: {
test: {
presets: [
'env'
],
}
},
}
当设置 BABEL_ENV=test 时,将用测试环境的配置(不含选项)替换根环境配置。
支持 class A extends Array(历史遗留问题)
Babel 将自动封装所有原生内置对象(如 Array、Error、HTMLElement 等),确保在编译类语法时能正确支持继承。
性能优化
preset-env: "useBuiltins": "usage"
babel-preset-env 不仅能根据目标环境编译语法,通过 useBuiltIns 选项还能按需添加目标环境不支持的 polyfill。
启用该选项后,如下代码:
import "babel-polyfill";
能够转换成
import "core-js/modules/es7.string.pad-start";
import "core-js/modules/es7.string.pad-end";
// ...
如果目标环境恰好支持除 padStart 或 padEnd 之外的其他 polyfill。
然而,为了更进一步优化,我们应该只导入代码库中实际"使用"的 polyfill。如果代码中根本没用到 padStart,那为什么要导入它呢?
"useBuiltins": "usage" 是我们实现按需加载的首个方案。它会在每个文件顶部动态导入 polyfill,但仅当检测到代码中实际使用时才导入。这种方式可确保应用仅加载必要的最小 polyfill 集合(且仅在目标环境不支持时才加载)。
例如代码中使用 Promise 时,若目标环境不支持,则会在文件顶部导入其 polyfill。打包工具会对相同模块进行去重,因此不会导致重复导入。
import "core-js/modules/es6.promise";
var a = new Promise();
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_ENV或process.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 仓库。同样感谢 Nicolo、Sven、Artem 和 Jessica 过去一年的大力支持。
我十分期待这次发布(也实在疲惫,毕竟耗时近一年 😝),但也不愿仓促行事。这个版本周期充满波折,但我收获颇丰,相信团队其他成员也是如此。
若说今年真正学到什么,那就是应该践行而非空谈这些感悟。
"Before you go maintaining anything else, maintain your own body first" - Mom 😸
— Henry Zhu (@left_pad) December 22, 2017


