This blog post describes the options you have for deploying ECMAScript 6 in current JavaScript environments. It is selective w.r.t. the amount of tools it covers. If you want a comprehensive list of tools, I suggest you look at Addy Osmani’s “ECMAScript 6 Tools”.
Consult the blog post “Using ECMAScript 6 today” for an overview of ES6 features.
What options do you have for using ECMAScript 6 today?
ECMAScript 6 features are continually appearing in engines. You can look up which ones are already supported where in Kangax’ “ECMAScript 6 compatibility table”. I’d expect first JavaScript engines to fully support ES6 in late 2015 or early 2016. It will take longer until all current engines do so.
Especially if you take support for legacy engines into consideration, compiling ES6 to ES5 will be the only viable option for using ES6 for quite a while. Compiling from source code to source code is also called transpiling. You can transpile ES6 either before deployment (statically) or at runtime (dynamically). The next section explains how that works, later sections describe other ES6 tools and libraries.
The nice thing about ES6 is that it is a superset of ES5, which means that all of your ES5 code bases are already valid ES6. This helps tremendously with adopting ES6-specific features, because you can do so incrementally.
As soon as the first engine fully supports ES6 and until all non-ES6 engines go away, a hybrid approach could be used for client-side apps:
npm may eventually support two versions of the same module, which would enable you to deliver libraries as both ES5 and ES6 for Node.js, io.js and client-side module systems that are based on npm.
There are three essential choices that you have to make for transpilation:
Note that the choices are not completely independent, not every module system works with every package manager etc. The next sections explain each of these choices in more detail.
A transpiler compiles your ES6 code to ES5. Popular choices are:
You can transpile the code either:
As a build step, TypeScript, Traceur and Babel let you produce ES5 code in the following module formats. You can either invoke them directly or use a build tool (grunt, gulp, broccoli, etc.).
In browsers, such ES5 modules are loaded via one of the module systems described later. On Node.js, you can use the built-in module system (other options exist, e.g. webpack and the ES6 Module Loader Polyfill).
In browsers, you transpile dynamically via a library plus a custom <script type="...">
. This option exists for Traceur and Babel.
For Node.js, Babel has tools for on-the-fly compilation. These are described in a separate blog post.
You need a package manager for installing third-party libraries. These are three popular ones:
Module systems bring support for modules to ES5 browsers (Node.js has a built-in module system). That way, you can build your app out of modules – your own and library modules. Popular module systems are:
Separate blog posts describe three example setups:
Test tools (such as Jasmine and mocha) can mostly be used as is, because they work with the transpiled code and don’t have to understand the original ES6 code. Babel’s documention has information on how to use it with various test tools.
The following linters all support ES6, but to varying degrees:
Shims/polyfills enable you to use much of the ECMAScript 6 standard library in ES5 code:
ES6 parsers:
There are many REPLs (command lines) out there for interactively playing with ES6. The obvious choices are the interactive online playgrounds of the following projects:
Additionally, Babel brings ES6 support to the Node.js REPL via its babel-node
tool.
ECMAScript 6 has three kinds of features:
For example:
These can be relatively easily compiled to ES5. For example, this is an ES6 class:
class Point {
constructor() {
this.x = x;
this.y = y;
}
toString() {
return `(${this.x}, ${this.y})`;
}
}
In loose mode, Babel produces nicer ES5 code, at the cost of not being completely faithful to ES6 semantics. This is the previous code, transpiled in loose mode:
"use strict";
var _classCallCheck = function (instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
};
var Point = (function () {
function Point() {
_classCallCheck(this, Point);
this.x = x;
this.y = y;
}
Point.prototype.toString = function toString() {
return "(" + this.x + ", " + this.y + ")";
};
return Point;
})();
For example:
These can be provided via a library. Much of that functionality (such as String.prototype.repeat()
) is even useful for ES5. A later section lists a few such libraries.
These features can never be transpiled completely faithfully. But some of them have reasonable simulations, for example:
let
and const
: are transpiled to var
plus renaming where necessary, to avoid name clashes. That is, immutability is usually not guaranteed.Object.keys()
) have to be patched to ignore property keys coming from symbols.Others are impossible to transpile (in a straightforward manner):
Error
and Array
)