7.10.0发布——预设-env中的类字段,"#private in "检查和更好的React树形晃动。

144 阅读8分钟

7.10.0发布:预设-env中的类字段,"#private in "检查和更好的React树形晃动

我们刚刚发布了Babel的一个新的小版本!

这个7.10版本包括:

  • 完全支持新的Stage 1提案,#prop in obj 检查私有字段提案
  • @babel/preset-env 现在可以将ES2015风格的Unicode转义( )编译成等效的传统语法( )。\u{Babe1}``\uDAAA\uDFE1
  • 可选链式运算符的两项改进 (?.)
  • 解析器支持新的Stage 1Module Attributes建议(import a from "./a.json" with type: "json")。
  • 对React代码更好的树形摇动支持(即React.memo )!
  • 设置RFCsrepo和GitHub讨论页面!

你可以在GitHub上阅读整个更新日志。

在发布Babel的同时,我们还发布了我们新的polyfills兼容架构的第一个实验版本(详情见下文),这要感谢Nicolò和社区中一些很棒的人一年多前,我们在Babel资源库的RFC问题中开始讨论这个问题。

另外,我们现在有一个官方的RFC程序来讨论对我们的用户有重大影响的变化:请在 babel/rfcs存储库中查看。此外,如果你有反馈或问题,我们已经在我们的仓库上启用了GitHub讨论

如果你或你的公司想支持Babel和JavaScript的发展,但不确定如何支持,你可以在我们的开放集体中为我们捐款,更好的是,直接与我们合作实现新的ECMAScript提案作为一个志愿者驱动的项目,我们依靠社区的支持来资助我们支持广大的JavaScript用户。如果你想讨论更多,请联系team@babeljs.io!

默认启用的新功能

解析为import.meta

现在它已经达到了第四阶段,import.meta的解析已经默认启用,这要感谢Kiko。请注意,@babel/preset-env 没有任何默认的转化支持,因为该对象包含什么由引擎决定,在ECMAScript规范中没有定义。

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

转换\u{...}-style Unicode escapes

我们还发现,我们没有支持编译一个5年前的ECMAScript特性:\u{...}-style Unicode escapes!感谢Justin,现在@babel/preset-env 可以默认在字符串和标识符中编译它们。

CodeSandbox上的例子

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

类属性和私有方法到@babel/preset-envshippedProposals 选项

最后,感谢Jùnliàng,我们将@babel/plugin-proposal-class-properties@babel/plugin-proposal-private-methods 加入到 的选项中。 shippedProposals@babel/preset-env 。这些建议还不是第四阶段(即ECMAScript标准的一部分),但它们已经在许多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 ,可以大大减少你的代码输出。

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

改进了可选链?. 人机工程学

TypeScript 3.9中,非空断言(postfix!)和可选链式之间的互动已经改变,以使其更有用。

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帮助实现这一点!


此外,类字段提案最近增加了对混合可选链?. 与私有字段的支持。这意味着下面的代码现在是有效的。

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

请注意,在第二个例子中,如果obj 不是nullish,并且没有#priv 字段,它仍然会抛出一个错误(与obj.#priv 抛出的完全一样)。你可以阅读下一节,看看如何避免它

in 中的私有字段

CodeSandbox上的例子

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

这个第一阶段的建议允许你静态地检查一个给定的对象是否有一个特定的私有字段。

私有字段有一个内置的 "品牌检查":如果你试图在一个没有定义它们的对象中访问它们,它将抛出一个异常。你可以通过使用try/catch 语句来确定一个对象是否有一个特定的私有字段,但是这个提议给了我们一个更紧凑和强大的语法来做到这一点。

你可以在提案的描述中阅读更多信息,并通过安装@babel/plugin-proposal-private-property-in-object 插件并将其添加到你的Babel配置中来测试这个提案。感谢Justin的PR!

模块属性解析器支持

模块属性提案(第一阶段)允许向引擎、模块加载器或捆绑器提供一些关于导入文件的额外信息。例如,你可以明确地指定它应该被解析为JSON。

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

此外,它们也可以与动态import() 。注意对尾部逗号的支持,以方便添加或删除第二个参数!

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

感谢Vivek,Babel现在支持解析这些属性:你可以在你的Babel配置中添加@babel/plugin-syntax-module-attributes 插件,或者,如果你直接使用@babel/parser ,你可以启用moduleAttributes 插件。目前,我们只接受type 属性,但将来我们可能会放宽这一限制,这取决于提案的发展情况。

ℹ️Babel不会转换这些属性,它们应该由你的捆绑器或自定义插件直接处理。目前,Babel模块的转化器忽略了这些属性。我们正在讨论是否应该在未来通过这些属性。

为React组件提供更好的树形晃动

React暴露了许多用于注释或包装元素的纯函数,例如React.forwardRefReact.memoReact.lazy 。然而,minifiers和bundlers并不知道这些函数是纯的,因此他们无法删除它们。

感谢Parcel团队的Devon@babel/preset-react ,现在在这些函数调用中注入了/*#__PURE__*/ 注释,以标记它们可以安全地被树形摇动。我们之前只对JSX本身做了这个(<a></a> =>/*#__PURE__*/React.createElement("a", null))

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

新的实验性polyfills架构

在过去的三年里,@babel/preset-env ,通过只转译语法特征和包括目标环境所需的core-js polyfills,帮助用户减少了捆绑的大小。目前Babel有三种不同的方式在源代码中注入core-js polyfills:

  • 通过使用@babel/preset-env'suseBuiltIns: "entry" 选项,可以为目标浏览器不支持的所有ECMAScript功能注入polyfills。
  • 通过使用useBuiltIns: "usage" ,Babel只会为不支持的ECMAScript功能注入polyfills,但前提是这些功能在输入源代码中确实被使用。
  • 通过使用@babel/plugin-transform-runtime ,Babel将为每一个由core-js 支持的ECMAScript特性注入ponyfills(它是 "纯 "的,不会污染全局范围)。这通常是由库作者使用的。

我们在JavaScript生态系统中的地位使我们能够进一步推动这些优化。与useBuiltIns 相比,@babel/plugin-transform-runtime 对一些用户有很大的优势,但它没有考虑目标环境:它是2020年,可能很少有人需要加载Array.prototype.forEach polyfill。

此外,我们为什么要限制只自动注入必要的polyfills到core-js ?还有DOM polyfills, Intl polyfills, 和无数其他网络平台API的polyfills。不是每个人都想使用core-js ;还有许多其他有效的ECMAScript polyfills,它们有不同的权衡标准(例如:源码大小与规范的兼容性),用户应该有能力使用他们选择的polyfill。例如,我们正在积极开发一个 es-shims集成。

如果注入它们的逻辑与可用或需要的polyfills的实际数据无关,从而使它们可以独立使用和开发,那会怎么样呢?

我们现在发布了四个新包的第一个实验性版本:

这些包都支持一个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上得到关于它们的反馈,但它们还没有准备好用于生产。例如,我们仍然需要对一些polyfills进行布线,而且我们还没有在生产应用中测试这些插件。