5.0.0 Released
In the past few months Babel has been welcomed into several major communities such as Node, React, Ember, Backbone, Angular, Rails, and many others. We launched the Users page only a few weeks ago and it's really cool to see everyone that is using it. Companies like CloudFlare, Netflix, Mozilla, and Yahoo!. Projects like Ghost, Atom, Mapbox, and so many more.
We've seen tons of blog posts, talks, events, courses all about ES6+ using Babel, and official Babel tools have been downloaded nearly 2 million times.
Today we are making by far the largest release of Babel ever.
If you're upgrading from Babel 4.x please see the breaking changes .
This release includes the new ES7 proposals:
The entire internal traversal and transformation pipeline has undergone a rewrite that substantially increases flexibility and will allow many future pipeline performance optimisations.
This release also brings a plugin API, this allows consumers to plug in their own custom transformers to utilise the powerful transformation mechanisms that Babel has to offer.
You can view the complete CHANGELOG here.
And as usual if you run into any regressions please report them immediately.
TC39 Processβ
In this release you'll start to see us aligned with the TC39 process. The TC39 is the technical committee from ECMA that writes the ECMAScript standard. Their process is categorised into 5 stages:
- Stage 0 - Strawman
- Stage 1 - Proposal
- Stage 2 - Draft
- Stage 3 - Candidate
- Stage 4 - Finished
Proposals that are stage 2 or above are enabled in Babel by default. Now this does not mean that they're guaranteed to be included in future ECMAScript specifications or even Babel itself. Stage 2 is considered a good point for inclusion by default in Babel due to their relative maturity and need for critical proposal feedback.
Now let's dive into the changes we made to 5.0.
Contents:
New Features
New Proposalsβ
Stage 0: Class Propertiesβ
Jeff Morrison's stage 0 class property initializers proposal fills the void of property composition on classes. These are analogous with the class properties example listed in the React 0.13 beta announcement.
Example:
classPerson{
firstName ="Sebastian";
static lastName ="McKenzie";
}
assert(newPerson().firstName,"Sebastian");
assert(Person.lastName,"McKenzie");
Usage:
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
Stage 1: Decoratorsβ
Yehuda Katz' stage 1 decorators proposal allows you to elegantly compose property descriptors and metadata decoration. In the future this will allow the powerful Ember Object Model to easily be represented with native classes.
Example:
functionconcat(...args){
let sep = args.pop();
returnfunction(target, key, descriptor){
descriptor.initializer=function(){
return args.map(arg=>this[arg]).join(sep);
}
}
}
functionautobind(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;
};
}
classPerson{
firstName ="Sebastian";
lastName ="McKenzie";
@concat("firstName","lastName"," ") fullName;
@concat("lastName","firstName",", ") formalName;
@autobind
getFullName(){
return`${this.firstName}${this.lastName}`;
}
}
assert(newPerson().fullName,"Sebastian McKenzie");
assert(newPerson().formalName,"McKenzie, Sebastian");
assert(newPerson().getFullName.call(null),"Sebastian McKenzie");
Usage:
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
Stage 1: Export Extensionsβ
Lee Byron's stage 1 additional export-from statements proposal completes the symmetry between import and export statement, allowing you to easily export namespaces and defaults from external modules without modifying the local scope.
Exporting a default
export foo from"bar";
equivalent to:
import_foofrom"bar";
export{ _foo as foo };
Exporting a namespace
export*as nsfrom"mod";
equivalent to:
import*as _nsfrom"mod";
export{ _ns as ns };
Usage:
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 Optimisationsβ
In preparation for React 0.14, Babel supports some optimisation transformers for JSX.
Constant Elements β
Starting with 0.14 ReactElements and their props objects can be treated as value types. i.e. any instance is conceptually equivalent if all their values are the same.
Take this function for example:
importReactfrom"react";
functionrender(){
return<div className="foo"/>;
}
This can be optimized by moving the JSX out of the function body so that each time it is called the same instance is returned:
importReactfrom"react";
var _ref =<div className="foo"/>;
functionrender(){
return _ref;
}
Not only does it allow us to reuse the same objects, React will automatically
bail out any reconciliation of constant components - without a manual
shouldComponentUpdate.
Usage:
require("babel").transform("code",{
optional:["optimisation.react.constantElements"]
});
$ babel --optional optimisation.react.constantElements script.js
Inline Elements β
Inline Elements should only be enabled in production as multiple React warning messages are suppressed which is extremely risky in development.
Starting with React 0.14 ReactElements can be inlined:
<div className="foo">{bar}<Baz key="baz"/></div>
as objects:
{type:'div',props:{className:'foo',children:
[ bar,{type:Baz,props:{},key:'baz',ref:null}]
},key:null,ref:null}
This improves performance over the existing React.createElement call by
inlining the result of it.
Usage:
require("babel").transform("code",{
optional:["optimisation.react.inlineElements"]
});
$ babel --optional optimisation.react.inlineElements script.js
.babelrcβ
Babel 5.0.0 has support for .babelrc out of the box across its entire
range of integrations. This means that it will work across
babel/register,
babel-node as well as across the entire range
of build system plugins and module loaders such as
babel-loader,
babelify, and others.
.babelrc is equivalent to JSHint's .jshintrc and
JSCS' .jscsrc.
{
"stage":1,
"ignore":[
"foo.js",
"bar/**/*.js"
]
}
See the docs for more info.
Plugin APIβ
5.0.0 also introduces the long anticipated plugin API. This allows you to hook into the powerful traversal and transformation internals of Babel. See the docs for more info.
Breaking Changes
Experimental Optionβ
The experimental option has been removed. Fear not though, there is a
replacement. Babel now categories the ES7 transformers by
TC39 stages.
tl;dr If you're using the experimental option, simply change it to
$ babel --stage 0 or { stage: 0 }.
Reminder: Proposals that are stage 2 or above are enabled by default.
Stage 0
es7.classPropertieses7.comprehensions
Stage 1
es7.asyncFunctionses7.decoratorses7.exportExtensionses7.objectRestSpread
Stage 2 (Stage 2 and above are enabled by default)
es7.exponentiationOperator
For a list of all current ES7 proposals please see the tc39/ecma262 repo.
returnUsedHelpers optionβ
The returnUsedHelpers option has been renamed to metadataUsedHelpers and the returning result
object has been changed from usedHelpers to metadata.usedHelpers.
Class Changesβ
5.0.0 introduces some updated derived class semantics that are long overdue.
super() must be called in a derived class constructor.
classFooextendsBar{
constructor(){
// no `super();`
}
}
Access to this before super() in a derived class constructor is not
allowed.
classFooextendsBar{
constructor(){
this.foo;// `this` access before `super();`
super();
}
}
super() is only allowed in derived class constructors.
classFoo{
constructor(){
super();// not in a derived constructor
}
}
Removed Featuresβ
- The playground has been removed so development can be focussed on mainstream ES features and proposals. This also reduces the risk of syntactic conflicts preventing certain official features from being implemented.
- Abstract references have been removed as the proposal has been superseded. Support for one or more of the superseding proposals may be implemented in the future.
In closing, we hope that you are now as excited about this release as we are. There's a lot that went into it, and we believe this will set us up for a long time into the future.
β The Babel team
Imports are now hoistedβ
In 4.x, imports were inlined as where they appeared in the code. Which means that this code:
global.test = 'test'
import './test'
would compile to:
'use strict';
global.test = 'test';
require('./test');
However, from 5.x on, this behaviour has been changed in order to comply with the ES6 spec and imports will now be hoisted . What this means in practical code is that the snippet above will get converted to something like:
'use strict';
require('./test');
global.test = 'test';
If your code required certain bits and pieces to be executed in between a specific module being imported -which might be the case while testing code and you need to fake some window properties :)- you may want to extract that away into its own file and import it before the code that needs it.