7.4.0 发布:支持 core-js 3、静态私有方法与部分应用
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
今天我们正式发布 Babel 7.4.0!
本次更新包含对 TypeScript 3.4 的支持、函数调用中的部分应用提案,以及静态私有方法功能。
我们在 @babel/parser 中增加了对语义化括号表达式的支持,并使其规范兼容性达到_空前_高度!
最后同样重要的是:@babel/preset-env 和 @babel/transform-runtime 现已支持 core-js@3,同时 @babel/template 新增了超赞的语法特性!
完整更新日志请查看 GitHub。
特别感谢所有新加入的 Babel 贡献者 😊。自从我们改用 GitHub Actions 生成更新日志后,未能及时在每次发布中致谢,但自 Babel 7.3.3 以来涌现了大量贡献者!
-
Babel 7.3.3: @Alec321, @mhcgrq, @ilyalesik, @yifei-fu
-
Babel 7.3.4: @elevatebart, @ian, @imjacobclark, @irohitb
-
Babel 7.4.0: @AmirS, @agoldis, @byara, @echenley, @tanohzana, @matt, @penielse, @pnowak
本版本的诸多功能由赞助商协作开发。Bloomberg 自 7.0 起每个版本都贡献了新型私有元素支持(7.1、7.2、7.3),本次更实现了静态私有方法!目前仅剩静态私有 getter/setter 待实现。
同样地,Trivago(OpenCollective 的基础支持赞助商)承接了部分应用插件的开发工作。
过去一个月,我们尝试与企业直接合作开发社区受益功能:RunKit 赞助 Nicolò 实现了 @babel/template 的占位符支持。
在管理大型开源项目时,并非所有工作都涉及代码:我们需要管理服务器、持续集成系统、社交媒体账户以及...大量密码!我们衷心感谢 1Password 接纳我们加入其开源支持计划,并为我们提供了免费的 1Password Teams 账户!
如果您或您的公司希望支持 Babel 和 JavaScript 生态的发展但不知从何入手,可以通过 OpenCollective 进行捐赠,更棒的是直接参与新 ECMAScript 提案的实现!作为志愿者驱动的项目,我们依赖社区支持来资助广大 JavaScript 用户群体,同时维护代码所有权。欢迎通过 henry@babeljs.io 联系 Henry 进一步交流!
core-js 3 (#7646)
我们因 @babel/preset-env 收获了许多赞誉,但这些荣誉更应归于 Denis 的卓越工作。他维护的 core-js 为 @babel/polyfill、@babel/runtime 和 @babel/preset-env 提供了所有垫片支持。
core-js@3 刚刚发布,包含大量新特性:您可以通过 "core-js@3, babel and a look into the future" 了解详情。除支持所有新提案外,现在还能通过 @babel/plugin-transform-runtime 为转换后的实例方法提供垫片,实现在旧版浏览器中无污染地使用:
// 'foo' could be either a string or an array, or a custom object
foo.includes("a");
// ⮕
import _includesInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/includes";
_includesInstanceProperty(foo).call(foo, "a");
@babel/preset-env 和 @babel/plugin-transform-runtime 现已支持提案的垫片:只需在配置中将 corejs: 3 替换为 corejs: { version: 3, proposals: true }。请注意 ECMAScript 提案具有不稳定性,未来可能在 core-js@4 中发生变化!
此前 @babel/preset-env 完全依赖 compat-table 数据确定特定环境需加载的垫片。core-js@3 引入了自带兼容性数据集及完整测试套件,将显著提升垫片精确度!
从 core-js@2 迁移
由于 core-js 的版本 2 与 3 互不兼容(避免破坏现有代码),新版不会默认启用。
-
If you are using
@babel/preset-env, you need to enable thecorejs: 3option:JavaScriptpresets: [
["@babel/preset-env", {
useBuiltIns: "usage", // or "entry"
corejs: 3,
}]
]Don't forget to update your installed version of
core-js!npm install --save core-js@3When using
core-js3, theuseBuiltIns: "entry"option not only transformsimport "core-js"imports, but alsoregenerator-runtime/runtimeand all the nestedcore-jsentry points.For example, when targeting Chrome 72, it will apply this transformation:
Input
JavaScriptimport "core-js/es";
import "core-js/proposals/set-methods";
import "core-js/features/set/map";Output
JavaScriptimport "core-js/modules/es.array.unscopables.flat";
import "core-js/modules/es.array.unscopables.flat-map";
import "core-js/modules/es.object.from-entries";
import "core-js/modules/esnext.set.difference";
import "core-js/modules/esnext.set.intersection";
import "core-js/modules/esnext.set.is-disjoint-from";
import "core-js/modules/esnext.set.is-subset-of";
import "core-js/modules/esnext.set.is-superset-of";
import "core-js/modules/esnext.set.map";
import "core-js/modules/esnext.set.symmetric-difference";
import "core-js/modules/esnext.set.union";Unlike when using
core-js2, it doesn't transform@babel/polyfillimports because when used directly that package loads version 2 ofcore-js. -
若使用
@babel/plugin-transform-runtime,需启用corejs: 3选项:JavaScriptplugins: [
["@babel/transform-runtime", {
corejs: 3,
}]
]可移除
@babel/runtime-corejs2,但需安装@babel/runtime-corejs3!npm remove @babel/runtime-corejs2
npm install --save @babel/runtime-corejs3 -
@babel/polyfill并非插件或预设,而是运行时包:若添加选项在core-js@2和core-js@3间切换,则需同时包含两个版本的包到最终产物。因此我们决定弃用它:现在你应当手动加载core-js作为 polyfill,并在转换生成器时加载regenerator-runtime/runtime:JavaScript// before
import "@babel/polyfill";
// after
import "core-js/stable";
import "regenerator-runtime/runtime";这种方式让你能自由选择版本,并可独立更新这两个包。
若感兴趣,可查看
@babel/polyfill中core-js@2的旧版源码:packages/babel-polyfill/src/index.js。
部分应用 (#9343 与 #9474)
本次发布包含对部分应用提案的 @babel/parser 与转换支持,该提案目前处于 Stage 1 阶段(上次更新于2018年7月)。所有实现工作由 Behrang Yarahmadi 完成,并由 Trivago 赞助。
此新特性允许你绑定函数的某些参数和 this 接收器,类似于现有的 Function#bind 方法但限制更少。
const half = divide(?, 2); // half = num => divide(num, 3)
half(6); // 3
element.addEventListener(
"click",
// handleEvent will be called with the correct "this".
this.handleEvent("click", ?) // e => this.handleEvent("click", e)
);
在与管道操作符提案(尤其是"minimal"或"F-sharp"变体)结合使用时特别有用,可避免大量箭头函数:
let newScore = player.score
|> add(?, 7)
|> clamp(0, 100, ?);
// Without this proposal:
let newScore = player.score
|> (_ => add(_, 7))
|> (_ => clamp(0, 100, _));
通过在配置中添加 @babel/plugin-proposal-partial-application 插件,或在线 REPL 中启用 stage 1 预设即可体验!
:::注意 尽管提案的README也描述了标签模板字面量的部分应用,但该功能尚未实现,因为它可能会被移除。 :::
静态私有方法 (#9446)
class Person {
static #is(obj) {
return obj instanceof Person;
}
constructor(name) {
if (Person.#is(name)) {
throw "It is already a person!";
}
}
}
再次感谢 Tim(Bloomberg)实现此提案!
若已使用实例私有方法,无需额外配置即可使用此新特性;否则需在插件列表中添加 @babel/plugin-proposal-private-methods。在线 REPL 中通过 stage-3 预设即可启用。
类私有特性支持距离全面完成仅差一步!😄
| Class Private | Instance | Static |
|---|---|---|
Fields class A { #a = 1 } | 7.0.0 | 7.1.0 |
Methods class A { #a() {} } | 7.2.0 | 7.4.0 |
Accessors class A { get #a() {} } | 7.3.0 | ✖️ |
TypeScript 3.4 RC 支持 (#9529 与 #9534)
TypeScript 3.4 RC 版本已于近日发布,感谢 Tan Li Hau 的贡献,Babel 已支持此版本!
类型注解新增两项特性:const 上下文(将对象标记为"深度冻结")及数组/元组的 readonly 修饰符。
const student = {
name: "Joe Blogs",
marks: [25, 23, 30]
} as const;
const vowels: readonly string[] = ["a", "e", "i", "o", "u"];
请注意,TypeScript 3.4 RC 并非稳定版本,建议等待 TypeScript 3.4 正式发布:您可订阅 TypeScript 博客获取发布通知。🙂
带括号表达式 (#8025)
括号通常对 JavaScript 编译器或代码生成器没有实质意义:它们仅是向解析器提示某些节点具有不同优先级的"标记符":
| Code | 1 + 2 * 3 / 1 + (2 * 3) | (1 + 2) * 3 |
|---|---|---|
| AST structure | ![]() | ![]() |
AST 生成后,操作优先级由树形结构而非原始括号决定:因此 Babel 此前未跟踪括号信息。
当打印 AST 时,@babel/generator 无法获知原始格式,仅会在必要时生成括号。
某些情况下这会给用户带来问题。例如使用 Google Closure Compiler 时,括号用于标记类型转换表达式:
/** @type {!MyType} */ (valueExpression)
我们已有表示括号的 ParenthesizedExpression 节点,但此前 @babel/parser 从未生成该节点,只能通过自定义插件注入。感谢 Erik Arvidsson 的工作,您现在可通过 parser 选项 启用 createParenthesizedExpressions 自动跟踪括号!
| Code | 1 + (2 * 3) | (1 + 2) * 3 |
|---|---|---|
| AST structure | ![]() | ![]() |
@babel/parser 规范合规性
Daniel 持续提升 @babel/parser 对 ECMAScript 规范的遵循度:现已通过 Test262 测试套件 98.97% 的用例。😎
本版本使 @babel/parser 支持识别 JavaScript 作用域规则:可准确获知变量声明状态、冲突检测、变量提升机制及特定语法结构在上下文中的合法性。
下列所有无效示例现均会被正确报错,无需在使用 @babel/parser 的工具中手动禁用:
let a, a; // Duplicate declaration 💥
if (foo) {
if (bar) { var b }
let b; // Duplicate declaration, again 💥
}
export { Foo }; // Error, Foo is not declared ❓
class C {
constructor() {
super(); // Super in a non-derived class 🤔
}
method(d, d) {} // Duplicate parameter 💥
}
代码占位符 (#9364)
代码并非总需人工直接编写:若需通过预定义模板生成代码呢?
模板文件常用于生成 HTML 代码,无论是使用 PHP 类语言还是 Handlebars 类模板引擎:
<!-- PHP -->
<section>
<h1><?= $title ?></h1>
<main><?= $body ?></main>
</section>
<!-- Handlebars -->
<section>
<h1>{{ title }}</h1>
<main>{{ body }}</main>
</section>
如果您开发过 Babel 插件,可能使用过 @babel/template:该工具可实现类似功能,但生成的是 JavaScript 代码:
const buildAssign = template`
var NAME = VALUE;
`;
const result = buildAssign({
NAME: varName,
VALUE: varValue,
});
此前 @babel/template 使用大写标识符作为"占位符"供后续替换。此方案在多数场景有效,但存在局限:
-
默认将所有大写标识符视为占位符,未替换时
@babel/template会抛出错误 -
无法在标识符非法位置(如函数体或导出声明处)插入占位符
为解决这些问题,我们引入了可替换任意节点的全新语法元素:%%placeholder_name%%
const buildLazyFn = template`
function %%name%%(%%params%%) {
return function () %%body%%;
}
`;
const result = buildLazyFn({
name: functionName,
params: functionParams,
body: functionBody,
});
此功能由 Stripe(通过 Runkit)赞助。我们正探索新的 Babel 赞助模式——这是首次由公司直接支付团队成员薪酬来实现特定功能。若贵公司希望赞助 ECMAScript 提案实现或 Babel 通用改进,请联系我们!



