So can I use ECMAScript 6 functionality right now? That’s the question everyone is asking these days. Many times when there is new browser functionality (like ES5, HTML5 or CSS3), advocates will spend a lot of time outlining all the new features and how great they are. But then at the end, you find out: "oh, but you can’t really use this functionality yet unless you using the latest Canary build that was just released yesterday." Talk about a letdown.
Support for ES6 functionality in JS engines is growing every week and kept up to date by Kangax’s ES6 compatibility matrix. However:
- ES6 support is still fairly low across browsers & servers (max is less than 70%)
- The features that are supported differ between browsers (with some overlap)
- None of the IE browsers significantly support ES6 (the new Microsoft Edge browser does)
As a result, you cannot yet reliable run ES6 natively client- or server-side. Your best bet is compiling your ES6 code down to ES5 using transpilation tools like Babel, Traceur, or TypeScript as part of your build process.
Continue you on if you want the details...
Upgrading to ES6
Axel Rauschmayer in his book Exploring ES6, mentions that getting the Web to upgrade to a new language is very challenging because there are multiple stakeholders who have very little control over each other:
The next group is filled with tens of thousands of web developers generating the code that becomes a pain in the JS engine implementers’ sides down the road. But we have our challenges as well. We have no control over what browsers our users are surfing the Web with. Some are keeping up to date with the latest Chrome or Firefox, while others are still on IE8 (for a host of semi-valid reasons).
Using ES6 natively
- While support is growing on a weekly basis, it is nowhere near 100% in any browser. As of writing, the top engine is (surprisingly) Microsoft’s Edge browser with only 68% support.
- There is only a small handful of features that are commonly supported across all of the engines, limiting the features you can “safely” use.
- None of the Internet Explorer browsers (from 11 on down) significantly support any ES6 features (and never plan to either). IE8 and below don’t even support ES5!
One would think: “hey, maybe if I limit the scope of my ES6 functionality to just the server that I have full control over I should be good!” In theory that would be a good idea, but as of now the JS-based servers (like Node.js & io.js) have the poorest level of ES6 support.
- A lot of what ES6 is introducing comes with new syntax. If your JS file uses that syntax, even if it does feature detection, executing the file will result in syntax errors if the JS engine doesn’t support the syntax.
- ES6 support differs greatly among JS engines, so support for a given feature does not serve as a proxy for support of some set of ES6 features you would like to use.
Kyle Simpson has released ES Feature Tests, but in order to use it you have to ensure that you’re testing for all of the features you plan to use in your ES6 file, which could be a maintenance nightmare. Moreover, you still need an ES5 version of your code to use when the feature detection fails.
For ES6 to ES5 transpilation, popular choices are:
- Traceur - the first ES6 to ES5 transpiler started by Google. As of today it only supports 59% of ES6 features.
- Babel - also an ES6 to ES5 transpiler that’s growing in popularity possibly because it also supports React’s JSX syntax. As of today it supports the most ES6 features at a somewhat respectable 73%.
If I had to pick one transpiler to go with, I would probably pick Babel. It’s got the greatest level of support (so you can use the greatest number of features), it supports JSX by React which is super powerful UI framework, and seems to have a more vibrant and growing community of development and support. But really you couldn’t go wrong with any of the options.
If you’re looking for a super quick way to get started with ES6 and you’re not trying to deploy code to production, dynamic transpilation is a great choice. Essentially it does the conversion from ES6 to ES5 at runtime right before your code is executed.
In the browser, to transpile dynamically, you would include the transpiler’s library plus include a specialized
<script> tag that would contain you ES6 code. Both Babel and Traceur support dynamic transpilation in the browser. In Node on the server, Babel supports this on-the-fly dynamic transpilation as well.
It’s worth reiterating that dynamic transpilation should only be used for experimental or development code. The overhead incurred from on-the-fly transpilation is too high to be viable in a production environment You shouldn’t force your users to compile your code every time when it isn’t even changing. Instead you should statically transpile your code.
If you want to actually use your ES6 code in a production environment, you need to transpile your ES6 code down to ES5 code as part of your server-side build process prior to deployment. What you end up deploying to your production environment will be the transpiled ES5 code. This build step could be invoked explicitly on the command line, on-demand by a file system watcher or as part of a greater build process via build tools like grunt, gulp, broccoli or others.
Babel, Traceur as well TypeScript all support static transpilation, generating an ES5 file in one of the following module formats:
Drawbacks of transpiling
- Transpiled code is often more bloated than the original code because it’s trying to recreate in ES5 what comes native in ES6. And in some cases the transpiled ES5 code is not only bigger than the source ES6 code, but is also bigger than ES5 code you would normally write. This is because when you write the code yourself, you can implement shortcuts and optimizations because you’ve written the entire code. Classes are a good example of this.
- Unlike code minification which just strips unnecessary whitespace and shortens local variables, transpiled code can be dramatically different than the original source code. A few lines of ES6 code can be dozens of lines of ES5 code and still need a polyfill to make it all work. So basically you’re running code in production that you didn’t write, which of course comes with some measure of risk. We’re accustomed to using libraries that we didn’t write, but not our own code. This risk should be mitigated by the fact that these transpilers are very well tested both by unit tests and by the developer community at large.
- Some ES6 functionality simply cannot be transpiled faithfully or without an additional large library. Features like
const, and symbols come to mind.
- IE8 does not support ES5. You shouldn't be supporting IE8, but if you are, your transpiled ES5 code may not work
- Lastly, if everyone is transpiling their code in order to be cross-browser compatible, the browsers themselves are never getting their ES6 features exercised; they are effectively still running ES5 code. Now I’m sure the browser vendors have their own plethora of tests that they run, but there’s huge value in having thousands of developers testing the browser by developing against the features. And until all of the non-ES6 browsers die out (which will be a while), it’s likely that the browsers’ ES6 features won’t get fully exercised for quite some time.
Most likely before you put in the effort to set up static transpilation as part of your build process you will want to at least play around with ES6 and see how it will transpile your code down to ES5. Furthermore, before you can even use transpilation for your app, you need to decide which transpiler you want to use. Thankfully there are many REPLs (an acronym for Read-Evaluate-Print Loop) that allow you to interactively play around with ES6, including ones for each of the transpilers we mentioned earlier:
- Babel REPL - ES6 playground based on Babel
- Traceur Transcoding Demo - ES6 playground based on Traceur
- TypeScript Playground - TypeScript playground that converts optionally typed ES6 code to ES5/ES3
- ES6 Fiddle - Allows you to type in ES6 code and have it converted to ES5 (built using Traceur)
- ES6 Repl - Chrome extension that allows you to work with ES6 code directly in the Chrome developer tools (also built using Traceur)
- babel-node module - Babel brings ES6 transpiling support to the Node.js REPL
Some things to consider before jumping all in on the ES6 bandwagon:
- Are you updating an existing app or starting something new? A new “greenfield” app is a better candidate for using ES6 so you don’t have a mix of ES5 and ES6 code, but if you set up your transpilation build process correctly, incrementally adding new ES6 files to an existing ES5 codebase shouldn’t be a problem either.
- If you’re part of a team, how familiar is the rest of the team with ES6? Introducing ES6 features and the transpilation build process to a team unfamiliar with ES6 could lead to confusion and could be a recipe for disaster. Have them go through this Learning ES6 series first!
Phew! That was a whirlwind overview! There are so many options when it comes to deploying an ES6 app that it’s hard to go deep on any one technology. But never fear! I’ve brought additional resources here:
- ES6 Support Matrix - an up-to-date list of which ES6 features each browser, server and transpiler supports
- ES6 Tools - a laundry list of ES6 tools by Addy Osmani that will point you in the right direction to more transpilers, plugins for the popular build tools, plugins for unit test libraries, module loaders, boilerplates, code generators, polyfills, and more!
- Client-side ES6 via webpack and Babel - documentation on an example transpilation setup using browsers, static transpilation, Babel and webpack
- Dynamically transpiled ES6 on Node.js via Babel - documentation on another example transpilation setup using dynamic transpilation, Node.js, and Babel
- Statically transpiled ES6 on Node.js via Babel and gulp - documentation on a third example transpilation setup using Node.js, static transpilation, Babel and gulp
That’s it! Hopefully this plethora of information will leave you feeling confident that you will be able to use ES6 right now via transpilation. And now as we begin deep diving into many of the ES6 features, we can also discuss which transpilers support the feature and what additional steps (if any) you need to perform to leverage the support. Happy (static) transpiling!