7.4.0发布:core-js 3、静态私有方法和部分应用
今天我们发布了Babel 7.4.0!
这个版本包括对TypeScript 3.4的支持,对函数调用中部分应用的建议,以及静态私有方法。
我们在@babel/parser ,增加了对有意义的括号表达式的支持,同时也使其比以往更符合规范!
最后但并非最不重要的是,@babel/preset-env 和@babel/transform-runtime 现在都支持core-js@3 ,而@babel/template 也有了一些可爱的新语法。
你可以在GitHub上阅读整个更新日志。
特别感谢所有新的Babel贡献者😊。自从我们开始使用GitHub动作生成版本更新日志以来,我们还没有机会在每个版本中感谢他们,但从Babel 7.3.3开始,他们已经是很多人了
- Babel 7.3.3:@Alec321,@mhcgrq,@ilyalesik,@yifei-fu
- 巴别网7.3.4。@elevatebart,@ian,@imjacobclark,@irohitb
- 巴别网7.4.0。@AmirS、@agoldis、@byara、@echenley、@tanohzana、@matt、@penielse、@pnowak
本版本中的许多功能都是与我们的赞助商合作开发的。 彭博社自7.0以来的每个版本(7.1、7.2、7.3)都支持一种新的私有元素,而且他们现在已经实现了静态私有方法这样就只剩下静态私有的getters和setters了。
同样地。 Trivago(OpenCollective上的一个基地支持赞助商)接管了部分应用程序插件的实现。
在过去的一个月里,我们一直在尝试在各种功能/优化上更直接地与公司合作,这将有利于社区。 奔跑吧一直在赞助Nicolò在@babel/template 中实现占位符支持。
当管理一个大型开源项目时,并不是所有的东西都是代码:我们需要管理服务器、持续集成、社交媒体账户和......大量的密码!我们真的很感激。我们非常感谢 1Password接受我们加入他们的开源支持计划,并为我们提供了一个免费的1Password团队账户。
如果你或你的公司想支持Babel和JavaScript的发展,但不确定如何支持,你可以在OpenCollective上向我们捐款,更好的是,你可以直接和我们一起实施新的ECMAScript提案!作为一个志愿者驱动的项目,我们依靠社区的支持,既为我们支持广大的JavaScript用户的努力提供资金,也为代码的所有权提供资金。如果你想进一步讨论,请联系Henry,henry@babeljs.io!
core-js 3
我们在@babel/preset-env 上的工作得到了很多赞誉,但其中大部分应该归功于Denis的出色工作。他维护的core-js ,提供了所有由@babel/polyfill 、@babel/runtime 和@babel/preset-env 所加载的polyfills。
core-js@3 在这里,你可以读到"core-js@3,babel和对未来的展望 "的内容。除了所有的新建议外,它还使使用 ,对转换@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 和 ,现在支持polyfilling建议:你只需要在你的配置中使用 ,而不是 。请记住,ECMAScript提案本身是不稳定的,可能会在 !@babel/plugin-transform-runtime corejs: { version: 3, proposals: true } corejs: 3 core-js@4
以前,@babel/preset-env 完全依靠compat-table 的数据来确定在特定的环境下需要加载哪些polyfills。core-js@3 引入了自己的兼容性数据集和一个详尽的测试套件,应该会使polyfilling更加准确。
移植自core-js@2
由于2 和3 的版本core-js 是不兼容的(我们不想破坏你的代码!),所以它没有默认启用。
-
如果你正在使用
@babel/preset-env,你需要启用corejs: 3选项。presets: [ ["@babel/preset-env", { useBuiltIns: "usage", // or "entry" corejs: 3, }] ]不要忘记更新你所安装的
core-js的版本 !npm install --save core-js@3当使用
core-js3,useBuiltIns: "entry"选项不仅可以转换import "core-js"的导入,还可以转换regenerator-runtime/runtime和所有嵌套的core-js的入口点。例如,当针对Chrome 72时,它将应用这种转换。
输入
import "core-js/es"; import "core-js/proposals/set-methods"; import "core-js/features/set/map";输出
import "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";与使用
core-js2时不同,它不会转换@babel/polyfill的导入,因为当直接使用该包时,会加载core-js的第二版。 -
如果你使用
@babel/plugin-transform-runtime,你需要使用corejs: 3选项。plugins: [ ["@babel/transform-runtime", { corejs: 3, }] ]你可以删除
@babel/runtime-corejs2,但你需要安装@babel/runtime-corejs3!npm remove @babel/runtime-corejs2 npm install --save @babel/runtime-corejs3 -
@babel/polyfill这不是一个插件或预设,而是一个运行时包:如果我们添加一个选项在 和 之间切换,两个包的版本都需要包含在你的包里。出于这个原因,我们决定取消它:你现在应该为polyfills加载 ,如果你正在转换生成器,则加载 。core-js@2core-js@3core-jsregenerator-runtime/runtime// before import "@babel/polyfill"; // after import "core-js/stable"; import "regenerator-runtime/runtime";这使你有能力加载你想要的任何版本,并独立地更新这两个包。
如果你有兴趣,你应该查看
@babel/polyfill的旧源码,以获取core-js@2:packages/babel-polyfill/src/index.js。
部分应用
这个版本包括对部分应用提案的@babel/parser 和转化支持,该提案目前处于第一阶段(最后一次提出是在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)
);
它与管道运算符的提议(尤其是在使用 "最小 "或 "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 ,或在在线复制中启用stage 1 预设来测试它。
ℹ️注意:尽管提案的readme也描述了部分应用于标记的模板字面,但它没有被实现,因为它可能会被删除。
静态私有方法
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 。当使用在线复制时,它是由stage-3 预设启用的。
类私有特性的支持离完成只有一步之遥了!😄
| 班级私有化 | 实例 | 静态 |
|---|---|---|
| 字段 | ||
class A { #a = 1 } | 7.0.0 | 7.1.0 |
| 方法 | ||
class A { #a() {} } | 7.2.0 | 7.4.0 |
| 访问者 | ||
class A { get #a() {} } | 7.3.0 | :heavy_multiplication_x: |
支持TypeScript 3.4 RC
TypeScript 3.4 RC已于几天前发布,感谢Tan Li Hau,它已经被Babel支持了
类型注释有两个新特性:const context,它将一个对象标记为 "深度冻结",以及数组和图元的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博客,以便在发布的时候得到通知。 🙂
圆括号表达式
对于JavaScript编译器或代码生成器来说,括号通常是没有意义的:它们只是 "提示",用来告诉解析器某些节点的优先级与默认的不同。
| 代码 | 1 + 2 * 3 /1 + (2 * 3) | (1 + 2) * 3 |
|---|---|---|
| AST结构 | ![]() | ![]() |
当AST生成后,操作的优先级由树状结构决定,而不是由原来的小括号决定:由于这个原因,Babel没有跟踪它们。
在打印AST时,@babel/generator ,不知道原始格式,只在需要的地方生成小括号。
在一些情况下,这会给用户带来问题。例如,在使用Google Closure Compiler时,小括号被用来标记类型转换表达式。
/** @type {!MyType} */ (valueExpression)
我们已经有一个ParenthesizedExpression 节点来表示小括号,但它从来没有被@babel/parser 生成,它只能被自定义插件注入。感谢Erik Arvidsson的工作,现在你可以使用createParenthesizedExpressions 解析器选项来自动跟踪它们了
| 代码 | 1 + (2 * 3) | (1 + 2) * 3 |
|---|---|---|
| AST结构 | ![]() | ![]() |
@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 💥
}
代码占位符
代码并不总是要由人类直接编写的:如果一些代码需要被生成,也许是使用预定义的模板呢?
模板文件经常被用来生成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的一般性改进,请联系我们



