[关闭]
@qinyun 2018-08-28T05:28:28.000000Z 字数 6288 阅读 1797

Babel 7.0正式发布,支持TypeScript,JSX Fragment

未分类


今天,Babel官方博客宣布正式推出Babel 7.0,在过去两年内,Babel 7经历了4000次提交,发布了50多个预览版本,这也是三年前发布v6.0之后的最大更新。

Babel的重要意义

由于JavaScript在不断地发展,各种新标准和提案也就层出不穷,用户使用的浏览器也不同(尤其是旧版的IE),这就导致了有些用户无法使用JavaScript的一些新特性,如果开发人员想使用新的语法(如class A {}),在旧浏览器上就会因为这个问题出现SyntaxError。

由于它能够转换JavaScript代码,还可用于实现新功能,因此它已成为TC39获得社区对JavaScript反馈的桥梁。

如今,Babel是JavaScript开发的基础。它在npm上,每月有1700万次的下载量,用户来自主流框架(React,Vue,Ember,Polymer)的开发者和企业(Facebook,Netflix,Airbnb)。即使你自己没有使用它,你的依赖项也很可能正在使用Babel。

Babel由志愿者驱动

虽然Babel对JavaScript语言的未来,甚至对社区和js生态都产生了巨大的影响,但你肯定想不到,他们的维护者只是由社区的几个志愿者组成。

重大变更

babel-upgrade

babel-upgrade是一个用于进行自动升级的新工具:目前在package.json和.babelrc配置文件中配置了依赖关系。

我们建议直接在git仓库上运行npx babel-upgrade,或者使用npm i babel-upgrade -g进行全局安装。

如果你想修改文件,可以使用参数--write和--install。

  1. npx babel-upgrade --write --install

JavaScript配置文件

我们引入了babel.config.js。

*.js配置文件在JavaScript生态系统中相当常见。ESLint和Webpack分别使用了.eslintrc.js和webpack.config.js配置文件。但这并不意味着它们就取代了.babelrc或package.json,这不是必要条件,但在某些情况下这可能很有用。以下是仅在“生产”环境中使用插件进行编译的配置。

  1. var env = process.env.NODE_ENV;
  2. module.exports = {
  3. plugins: [
  4. env === "production" && "babel-plugin-that-is-cool"
  5. ].filter(Boolean)
  6. };

babel.config.js的配置解析方式与.babelrc不同。它始终会解析该文件中的配置,而不会从每个文件向上查找,直到找到配置为止。这样就可以利用overrides特性。

使用overrides进行选择性配置

  1. module.exports = {
  2. presets: [
  3. // defeault config...
  4. ],
  5. overrides: [{
  6. test: ["./node_modules"],
  7. presets: [
  8. // config for node_modules
  9. ],
  10. }, {
  11. test: ["./tests"],
  12. presets: [
  13. // config for tests
  14. ],
  15. }]
  16. };

有些应用程序需要针对测试、客户端代码和服务器代码使用不同的编译配置选项,通过这种方式就不需要在每个文件夹下创建.babelrc文件了。

速度

我们做了很多变更来优化代码,并接受了来自V8团队的一些补丁(https://twitter.com/rauchg/status/924349334346276864)。

输出选项

Babel支持预设和插件选项有一段时间了。比如,你可以将插件包装在一个数组中,并将选项对象传给插件:

  1. //减号表示移除,加号表示增加:
  2. {
  3. "plugins": [
  4. - "pluginA",
  5. + ["pluginA", {
  6. + // options here
  7. + }],
  8. ]
  9. }

我们对部分插件的loose选项做了一些修改,并为部分插件添加了一些新选项!

比如,对于类class A {},现在不包含_classCallCheck。

  1. class A {}
  2. -------------------
  3. //减号表示移除:
  4. var A = function A() {
  5. - _classCallCheck(this, A);
  6. };

如果for-of循环的是一个数组,那么可以使用这个新选项:[“transform-for-of”,{“assumeArray”:true}]

  1. let elm;
  2. for (elm of array) {
  3. console.log(elm);
  4. }
  5. ----------------------
  6. let elm;
  7. for (let _i = 0, _array = array; _i < _array.length; _i++) {
  8. elm = _array[_i];
  9. console.log(elm);
  10. }

在loose模式下将transform-typeof-symbol插件排除在外。

“纯粹”的注解支持

转换后的ES6类使用/#PURE/进行注解,这样就可以告诉Uglify和babel-minify移除死代码。这些注解也被添加到其他辅助函数中。

  1. class C {
  2. m() {}
  3. }
  4. ---------------------
  5. var C =
  6. /*#__PURE__*/
  7. function () {
  8. // ...
  9. }();

TC39提案支持

以下是Babel支持的一些新语法以及已经添加到v7中的语法清单:

TypeScript支持(@babel/preset-typescript)

我们与TypeScript团队合作,让Babel使用@babel/preset-typescript解析/转换类型语法,类似于我们使用@babel/preset-flow处理Flow的方式。

之前(有类型):

  1. interface Person {
  2. firstName: string;
  3. lastName: string;
  4. }
  5. function greeter(person : Person) {
  6. return "Hello, " + person.firstName + " " + person.lastName;
  7. }

之后(移除了类型):

  1. function greeter(person) {
  2. return "Hello, " + person.firstName + " " + person.lastName;
  3. }

JSX Fragment支持(<>)

正如React博客中所提到的,从Beta.31开始,已经支持JSX Fragment。

  1. render() {
  2. return (
  3. <>
  4. <ChildA />
  5. <ChildB />
  6. </>
  7. );
  8. }
  9. -----------------------
  10. // output
  11. render() {
  12. return React.createElement(
  13. React.Fragment,
  14. null,
  15. React.createElement(ChildA, null),
  16. React.createElement(ChildB, null)
  17. );
  18. }

Babel辅助函数的变化

@babel/runtime已经被分为@babel/runtime和@babel/runtime-corejs2。前者仅包含Babel的辅助函数,后者包含辅助函数以及polyfill函数(例如Symbol、Promise)。

规范规定了需要通过new Person()实例化一个类,但如果它被编译成一个函数,就可以直接调用Person(),所以我们提供了一个运行时检查。

  1. class Person {}
  2. ------------------------
  3. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  4. var Person = function Person() {
  5. _classCallCheck(this, Person);
  6. };

使用@babel/plugin-transform-runtime和@babel/runtime(作为依赖项),Babel可以提取单个函数,而且只需要模块函数来获得较小的输出,如下所示:

  1. var _classCallCheck = require("@babel/runtime/helpers/classCallCheck");
  2. var Person = function Person() {
  3. _classCallCheck(this, Person);
  4. };

自动polyfill(实验性质)

要使用polyfill,只需导入@babel/polyfill即可:

  1. import "@babel/polyfill";

但这样会导入整个polyfill,如果浏览器已经支持某些特性,就不需要导入所有内容。我们可以使用选项useBuiltins:”entry”来导入需要用到的部分。

我们可以更进一步,通过选项useBuiltIns:”usage”只将需要用到的polyfill导入到代码库中。

它将遍历每个文件,并在每个使用了内置polyfill的文件的顶部注入一个导入语句。例如:

  1. import "core-js/modules/es6.promise";
  2. var a = new Promise();

但它的推理不是很完美,可能会出现误报:

  1. import "core-js/modules/es7.array.includes";
  2. a.includes // assume a is an []

Babel宏

Babel的一大特点是它的可插拔性。多年来,Babel从一个“6to5”编译器转变为代码转换平台,为用户和开发人员提供了出色的优化选项。人们已经为特定库和用例开发了大量的Babel插件,用以提升库API的性能和功能。

可惜的是,将这些插件添加到代码库中需要更改配置,从而增加了代码复杂性。由Kent C. Dodds开发的babel-plugin-macros(https://github.com/kentcdodds/babel-plugin-macros)已经解决了这个!

在安装了babel-plugin-macros并将其添加到配置中(它已包含在create-react-app v2中)之后,你就不必费心配置就可以使用宏了。此外,为特定应用程序或代码编写自定义转换也变得更加容易。

模块目标

Babel一直试图在转换的影响范围和功能之间做出平衡。在Babel 7中,通过配置Babel来支持模块/非模块模式变得更加容易。

值得注意的是,一些流行的Web框架的CLI工具已经在利用这些支持,这让转换后的JavaScript代码减少了大约20%。

class C extends HTMLElement {}

Babel总是会警告说它不支持扩展原生内置元素(Array、Error等),但现在可以了!我们对类插件进行了修改,如果你使用了preset-env,那么默认就自动启用了这个特性。

网站变更

我们将我们的网站从Jekyll(https://jekyllrb.com/)搬到了Docusaurus(https://docusaurus.io/)!

REPL

我们将REPL重写为React组件,并更好地与CodeSandbox集成。这样你就可以在REPL中安装来自npm的任何插件或预设,并获取CodeSandbox的任何更新。

我们有了自己的主题歌

有一天,Angus给我们传了一首很棒的歌,于是我们就把它作为我们的“主题歌”?Shawn还制作了一张很精彩的封面(https://www.youtube.com/watch?v=40abpedBKK8)。

这首歌可以在代码库的SONG.md(https://github.com/babel/babel/blob/master/SONG.md)中找到。

接下来要做些什么

Babel本质上就是要与JavaScript紧紧联系在一起,包括在语法变得“稳定”之前花时间和精力来实现和维护语法。我们关心的是整个过程:升级路径、新特性的传播、标准/语言设计的教学、易用性以及与其他项目的集成。

在Nicolò的帮助下,我们几乎完成了新的装饰器的实现。这是一个漫长的旅程(我们已经花了一年多的时间!),因为新的提案完全不同,而且比旧的更强大。它可能会在下一个次要版本中发布。

还有很多新特性还在开发当中:插件顺序、更好的验证/错误、速度提升、新的loose/spec选项、缓存、异步使用Babel、从CI构建、冒烟测试、运行test262。

开源是一面镜子

如果我们有足够的时间和资源来完成所有这些想法并且做得好,那就太好了。但正如我们在当前版本中所展示的那样,完整这些工作需要比预期更长的时间!或许是因为我们对自己设定了太高的期望。但不管怎样,努力实现这一版本是非常值得的。

原文链接

https://babeljs.io/blog/2018/08/27/7.0.0

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注