跳至主内容

7.10.0 版本发布:preset-env 支持类字段、'#private in' 私有字段检查及更好的 React 摇树优化

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

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

我们刚刚发布了 Babel 的新次版本更新!

本次 7.10 版本包含:

  • 完整支持 Stage 1 新提案 #prop in obj 私有字段检查功能 提案链接

  • @babel/preset-env 现在可将 ES2015 风格的 Unicode 转义符 (\u{Babe1}) 编译为等效的传统语法 (\uDAAA\uDFE1)

  • 可选链操作符 (?.) 的两项优化

  • 支持解析 Stage 1 新提案模块属性提案 (import a from "./a.json" with type: "json")

  • 更好的 React 代码摇树优化支持 (如 React.memo)!

  • 设立 RFCs 仓库GitHub 讨论区!

您可在 GitHub 查看完整更新日志

伴随本次 Babel 发布,我们特别感谢 Nicolò 及社区杰出贡献者,推出了首个实验版本的新 polyfill 兼容架构(详见下文)!相关讨论始于一年前 Babel 仓库中的 RFC issue

另外,我们现已建立官方 RFC 流程,用于讨论对用户有重大影响的变更:请访问 babel/rfcs 仓库查看详情!同时,我们在仓库启用了 GitHub 讨论区,欢迎您提出反馈或疑问!

若您或公司希望支持 Babel 及 JavaScript 生态发展,可通过 Open Collective 进行捐赠,更可直接参与新 ECMAScript 提案的实现!作为志愿者驱动的项目,我们依赖社区支持来服务广大 JavaScript 用户。欢迎通过 team@babeljs.io 联系我们!

默认启用的新功能

支持解析 import.meta

Kiko 的贡献下,import.meta 解析功能现默认启用(该提案已进入 Stage 4)。请注意 @babel/preset-env 默认不支持其转换功能,因为该对象内容取决于具体引擎实现,未在 ECMAScript 规范中定义

JavaScript
console.log(import.meta); // { url: "file:///home/user/my-module.js" }

Transforming ​u{...}-style Unicode escapes (#11377)

我们还修复了长达五年的功能缺失:感谢 Justin@babel/preset-env 现在默认支持编译 \u{...} 风格的 Unicode 转义符(适用于字符串和标识符)

CodeSandbox 示例

JavaScript
var \u{1d49c} = "\u{Babe1}";
console.log(\u{1d49c});
JavaScript
var _ud835_udc9c = "\uDAAA\uDFE1";
console.log(_ud835_udc9c);

类属性与私有方法支持纳入 @babel/preset-envshippedProposals 选项 (#11451)

最后,感谢 Jùnliàng 的贡献,我们已将 @babel/plugin-proposal-class-properties@babel/plugin-proposal-private-methods 添加到 @babel/preset-envshippedProposals 选项中。这些提案尚未进入 Stage 4(即还不是 ECMAScript 标准),但已在众多 JavaScript 引擎中默认启用。

如果您还不熟悉:

JavaScript
class Bork {
// Public Fields
instanceProperty = "bork";
static staticProperty = "babelIsCool";
// Private Fields
#xValue = 0;
a() {
this.#xValue++;
}

// Private methods
get #x() { return this.#xValue; }
set #x(value) {
this.#xValue = value;
}
#clicked() {
this.#x++;
}
}

若您错过了上个版本,在 7.9 中我们新增了选项"bugfixes": true,该选项能显著减少代码输出量。

JavaScript
{
"presets": [
["@babel/preset-env", {
"targets": { "esmodules": true }, // Use the targets that you was already using
"bugfixes": true // will be default in Babel 8
}]
]
}

改进可选链 ?. 的使用体验 (#10961, #11248)

TypeScript 3.9 中,非空断言(后缀 !)与可选链的交互行为已更改,使其更具实用性。

foo?.bar!.baz

在 TypeScript 3.8 和 Babel 7.9 中,上述代码会被解析为 (foo?.bar)!.baz:"若 foo 非空值,则获取其 .bar 属性。随后信任 foo?.bar 永不为空并始终获取其 .bar 属性"。这意味着当 foo 为空值时,该代码将始终抛出错误,因为我们试图从 undefined 获取 .baz

在 TypeScript 3.9 和 Babel 7.10 中,该代码行为类似于 foo?.bar.baz:"若 foo 非空值,则获取其 .bar.baz 属性,并相信我 foo?.bar 不为空值"。感谢 Bruno 协助实现此功能!


此外,类字段提案近期新增支持将可选链 ?. 与私有字段结合使用。这意味着以下代码现已合法:

JavaScript
obj?.property.#priv;
obj?.#priv;

注意在第二个示例中,若 obj 非空值但不包含 #priv 字段,仍会抛出错误(与 obj.#priv 的行为一致)。您可阅读下一节了解如何规避此问题!

私有字段的 in 运算符支持 (#11372)

CodeSandbox 示例

JavaScript
class Person {
#name;

hug(other) {
if (#name in other) console.log(`${this.#name} 🤗 ${other.#name}`);
else console.log("It's not a person!")
}
}

此 Stage 1 提案允许您静态检查指定对象是否包含特定私有字段。

私有字段内置"品牌检查"机制:若尝试在未定义该字段的对象中访问它,将抛出异常。您可通过 try/catch 语句利用此行为判断对象是否包含特定私有字段,而本提案提供了更简洁且健壮的语法实现此功能。

你可以在提案描述中了解更多详情。要测试此提案,请安装 @babel/plugin-proposal-private-property-in-object 插件并添加到 Babel 配置中。感谢 Justin 的 PR 贡献!

模块属性解析器支持 (#10962)

模块属性提案(Stage 1 阶段)允许为引擎、模块加载器或打包器提供导入文件的附加信息。例如,可以显式指定文件应作为 JSON 解析:

JavaScript
import metadata from "./package.json" with type: "json";

该特性也可用于动态 import() 调用。注意支持尾随逗号的设计,这使添加/删除第二个参数更加便捷!

JavaScript
const metadata = await import(
"./package.json",
{ with: { type: "json" } },
);

感谢 Vivek 的贡献,Babel 现已支持解析这些属性:你可以在 Babel 配置中添加 @babel/plugin-syntax-module-attributes 插件;若直接使用 @babel/parser,则可启用 moduleAttributes 插件。目前我们仅接受 type 属性,未来可能根据提案演进放宽此限制。

信息

Babel 不会_转换_这些属性,它们应由你的打包器或自定义插件处理。当前 Babel 的模块转换器会_忽略_这些属性。我们正在讨论未来是否应透传这些属性。

React 组件树摇动优化 (#11428)

React 提供了众多用于注解或包装元素的纯函数,例如 React.forwardRefReact.memoReact.lazy。但压缩工具和打包器无法识别这些函数的纯度,因此无法移除它们。

感谢 Parcel 团队的 Devon@babel/preset-react 现在会在这些函数调用处注入 /*#__PURE__*/ 标注,标记它们可安全进行树摇动优化。此前我们仅对 JSX 本身应用此优化(例如 <a></a> 转为 /*#__PURE__*/React.createElement("a", null))。

JavaScript
import React from 'react';
const SomeComponent = React.lazy(() => import('./SomeComponent'));
JavaScript
import React from 'react';
const SomeComponent = /*#__PURE__*/React.lazy(() => import('./SomeComponent'));

实验性 polyfill 新架构 (#10008, babel-polyfills)

过去三年中,@babel/preset-env 通过仅转译目标环境需要的语法特性并注入 core-js polyfill,有效帮助用户缩减包体积。当前 Babel 提供三种不同的 core-js polyfill 注入方式:

  • 使用 @babel/preset-envuseBuiltIns: "entry" 选项,可为目标浏览器不原生支持的所有 ECMAScript 功能注入 polyfill;

  • 使用 useBuiltIns: "usage" 选项时,Babel 仅对源代码中实际使用的、且目标环境不支持的 ECMAScript 特性注入 polyfill;

  • 使用 @babel/plugin-transform-runtime 时,Babel 会为 core-js 支持的所有已用 ECMAScript 特性注入 "纯净" ponyfills(不会污染全局作用域),该方式通常被库作者采用。

我们在 JavaScript 生态中的独特位置,让我们能将这些优化推向更深层次。对部分用户而言,@babel/plugin-transform-runtime 相比 useBuiltIns 具备显著优势,但它未考虑目标环境:如今已是 2020 年,几乎没人需要加载 Array.prototype.forEach 的 polyfill。

此外,为何要将自动注入必要 polyfill 的能力局限在 core-js?还有 DOM polyfill、Intl polyfill 以及无数其他 Web 平台 API 的 polyfill。并非所有人都想使用 core-js;存在多种 ECMAScript polyfill 方案,它们各有取舍(例如源码体积与规范兼容性的权衡),用户理应有选择 polyfill 的自由。例如,我们正积极推进与 es-shims 的集成。

如果注入逻辑能与 polyfill 的实际可用性/需求数据解耦,使其可独立使用和开发,会如何?

我们现在发布四个新软件包的实验性初版:

这些包均支持通过 method 选项调整注入方式(类似于 @babel/preset-env@babel/plugin-transform-runtime 现有功能)。您可将 polyfill 注入入口点(仅限全局作用域)或通过代码直接使用(支持全局作用域和"纯"模式)。下方自定义的 CodeSandbox 可让您体验不同 polyfill 选项的差异。

image

我们还发布了 @babel/helper-define-polyfill-provider:全新的辅助工具包,让 polyfill 作者和用户能定义_专属的_ polyfill 提供者插件。

特别感谢 JordanNicolò 协作,使构建 es-shims 插件成为可能!

提示

若需深入了解这些包并学习配置方法,请查阅项目的 README

注意

这些包仍处于实验阶段。欢迎在 Twitter 或 GitHub 提交反馈,但请勿用于生产环境。例如,部分 polyfill 仍需接入,且尚未在生产应用中测试插件稳定性。