5.0.0版发布
在过去的几个月里,Babel受到了几个主要社区的欢迎,如Node、React、Ember、Backbone、Angular、Rails和其他许多社区。我们在几周前才推出了用户页面,看到每个人都在使用它,这真的很酷。像CloudFlare、Netflix、Mozilla和Yahoo!等公司。像Ghost、Atom、Mapbox等项目,还有很多。
我们已经看到了大量关于使用Babel的ES6+的博客文章、讲座、活动和课程,官方的Babel工具已经被下载了近200万次。
今天,我们正在制作迄今为止最大的Babel版本。
如果您是从Babel 4.x升级过来的,请看突发变化。
整个内部遍历和转换管道经历了一次重写,大大增加了灵活性,并将允许许多未来管道的性能优化。
这个版本还带来了一个插件API,这使得消费者可以插入他们自己的自定义转化器,以利用Babel所提供的强大的转化机制。
你可以在这里查看完整的变化日志。
像往常一样**,如果你遇到任何回归问题,请立即报告**。
TC39进程
在这个版本中,你会看到我们开始与TC39进程保持一致。TC39是ECMA的一个技术委员会,负责编写ECMAScript标准。他们的流程分为5个阶段。
- 第0阶段 - 草稿
- 第1阶段 - 提案
- 第二阶段 - 草案
- 第三阶段 - 候选
- 第四阶段 - 完成
第二阶段或以上的提案在Babel中是默认启用的。但这并不意味着它们一定会被纳入未来的ECMAScript规范,甚至是Babel本身。第二阶段被认为是默认纳入Babel的好时机,因为它们相对成熟,需要关键的提案反馈。
现在让我们深入了解我们对5.0所做的修改。
新功能
新建议
第0阶段:类属性
Jeff Morrison的第0阶段的类属性初始化器提案填补了类上属性组成的空白。这些类似于React 0.13测试版公告中列出的类属性例子。
例子
class Person {
firstName = "Sebastian";
static lastName = "McKenzie";
}
assert(new Person().firstName, "Sebastian");
assert(Person.lastName, "McKenzie");
使用方法
require("babel").transform("code", {
optional: ["es7.classProperties"]
});
// or
require("babel").transform("code", { stage: 0 });
$ babel --optional es7.classProperties script.js
# or
$ babel --stage 0 script.js
第一阶段装饰器
Yehuda Katz的第1阶段装饰器建议允许你优雅地组成属性描述符和元数据装饰。在未来,这将使强大的Ember对象模型能够轻松地用本地类来表示。
例子
function concat(...args) {
let sep = args.pop();
return function(target, key, descriptor) {
descriptor.initializer = function() {
return args.map(arg => this[arg]).join(sep);
}
}
}
function autobind(target, key, descriptor) {
var fn = descriptor.value;
delete descriptor.value;
delete descriptor.writable;
descriptor.get = function () {
var bound = fn.bind(this);
Object.defineProperty(this, key, {
configurable: true,
writable: true,
value: bound
});
return bound;
};
}
class Person {
firstName = "Sebastian";
lastName = "McKenzie";
@concat("firstName", "lastName", " ") fullName;
@concat("lastName", "firstName", ", ") formalName;
@autobind
getFullName() {
return `${this.firstName} ${this.lastName}`;
}
}
assert(new Person().fullName, "Sebastian McKenzie");
assert(new Person().formalName, "McKenzie, Sebastian");
assert(new Person().getFullName.call(null), "Sebastian McKenzie");
使用方法
require("babel").transform("code", {
optional: ["es7.decorators"]
});
// or
require("babel").transform("code", { stage: 1 });
$ babel --optional es7.decorators script.js
# or
$ babel --stage 1 script.js
阶段1:导出扩展
Lee Byron的第1阶段额外的export-from语句提案完成了import和export语句之间的对称性,允许你轻松地从外部模块导出命名空间和默认值,而无需修改本地范围。
导出一个缺省
export foo from "bar";
相当于。
import _foo from "bar";
export { _foo as foo };
导出一个命名空间
export * as ns from "mod";
相当于
import * as _ns from "mod";
export { _ns as ns };
用法
require("babel").transform("code", {
optional: ["es7.exportExtensions"]
});
// or
require("babel").transform("code", { stage: 1 });
$ babel --optional es7.exportExtensions script.js
# or
$ babel --stage 1 script.js
React优化
在为React 0.14做准备时,Babel支持JSX的一些优化转换器。
常量元素
从0.14版本开始,ReactElements和它们的props对象可以被视为价值类型,即任何实例在概念上都是等价的,如果它们的值都是一样的。
以这个函数为例。
import React from "react";
function render() {
return <div className="foo" />;
}
这可以通过将JSX移出函数体进行优化,这样每次调用时都会返回相同的实例。
import React from "react";
var _ref = <div className="foo" />;
function render() {
return _ref;
}
这不仅允许我们重复使用相同的对象,React会自动跳出任何调和的常量组件--无需手动shouldComponentUpdate 。
使用方法
require("babel").transform("code", {
optional: ["optimisation.react.constantElements"]
});
$ babel --optional optimisation.react.constantElements script.js
内联元素
仅限生产
Inline Elements应该只在生产中启用,因为多个React警告信息被压制,这在开发中是非常危险的。
从React 0.14开始,ReactElements可以被内联:
<div className="foo">{bar}<Baz key="baz" /></div>
作为对象:
{ type: 'div', props: { className: 'foo', children:
[ bar, { type: Baz, props: { }, key: 'baz', ref: null } ]
}, key: null, ref: null }
这比现有的React.createElement ,通过内联它的结果来提高性能。
使用方法
require("babel").transform("code", {
optional: ["optimisation.react.inlineElements"]
});
$ babel --optional optimisation.react.inlineElements script.js
.babelrc
Babel 5.0.0支持.babelrc ,在其整个集成范围内。这意味着,它将在以下方面发挥作用 babel/register, babel-node以及整个构建系统的插件和模块加载器,如 babel-loader, babelify和其他。
.babelrc 相当于JSHint的 .jshintrc和JSCS的 .jscsrc.
{
"stage": 1,
"ignore": [
"foo.js",
"bar/**/*.js"
]
}
更多信息见文档。
插件API
5.0.0还引入了期待已久的插件API。这使你能够钩住Babel强大的遍历和转换内部。更多信息请参见文档。
破坏性变化
实验性选项
experimental 选项已被删除。不过不用担心,有一个替代品。Babel现在按TC39阶段对ES7变压器进行分类。
tl;dr 如果你正在使用experimental 选项,只需将其改为$ babel --stage 0 或{ stage: 0 } 。
提醒大家。 阶段2或以上的提案是默认启用的。
阶段0
es7.classPropertieses7.comprehensions
第一阶段
es7.asyncFunctionses7.decoratorses7.exportExtensionses7.objectRestSpread
第2阶段(第2阶段及以上的提案是默认启用的)
es7.exponentiationOperator
关于所有当前ES7提案的列表,请参见tc39/ecma262 repo。
returnUsedHelpers 选项
returnUsedHelpers 选项已被重新命名为metadataUsedHelpers ,返回的结果对象已从usedHelpers 改为metadata.usedHelpers 。
类的变化
5.0.0引入了一些早该更新的派生类语义。
super() 必须在派生类的构造函数中调用。
class Foo extends Bar {
constructor() {
// no `super();`
}
}
在派生类构造函数中,不允许在super() 之前访问this 。
class Foo extends Bar {
constructor() {
this.foo; // `this` access before `super();`
super();
}
}
super() 只允许在派生类构造函数中使用。
class Foo {
constructor() {
super(); // not in a derived constructor
}
}
删除的功能
- 游乐场已经被移除,因此开发可以集中在主流的ES功能和建议上。这也降低了语法冲突的风险,使某些官方特性无法实现。
- 抽象引用已被删除,因为该提议已被取代。对一个或多个被取代的提案的支持可能会在未来实施。
最后,我们希望你现在和我们一样对这个版本感到兴奋。这里面有很多东西,我们相信这将为我们在未来很长一段时间内的发展奠定基础。
- 巴别尔团队
进口现在被吊起来了
在4.x ,进口是按照它们在代码中出现的位置进行内联。这意味着,这段代码。
global.test = 'test'
import './test'
将被编译为:
'use strict';
global.test = 'test';
require('./test');
然而,从5.x 开始,为了符合ES6规范,这种行为已经改变, *现在导入*将 被吊起。这意味着在实际代码中,上面的片段将被转换为类似的东西。
'use strict';
require('./test');
global.test = 'test';
如果你的代码需要在特定模块被导入之间执行某些片段--这可能是测试代码时的情况,你需要伪造一些window 属性:)--你可能想把它提取到自己的文件中,并在需要它的代码之前导入。