How to JavaScript? (or yet another JavaScript guide) Part 5 - ES6 and beyond with Babel

In Part 4 we looked at webpack-dev-server, what it can do for us, and how easy it is to add it to our project. Now in this article we’ll talk about how we can support “future” JavaScript features in our project by using Babel, while also allowing us to maintain compatibility with older browsers via code transpiling.

JavaScript, like any other language, is evolving and getting new features (check ES6 and ES7), yet as front-end developers we live in an interesting situation, where we can’t just start using those new features, since we risk writing code using features that are not supported by the browsers of the end users. For example, according to ES6 specification, it says that we can use the keyword class to define a class in a more OOP-oriented manner, like so:

class Potato {
constructor(weight) {
this.weight = weight;
}
}
const potato = new Potato(1);

If I try to run this code by executing it in Firefox 44.0.2's console it won’t work, saying “class is a reserved identifier”, but if I run this same code in FirefoxDeveloperEdition 46.0a2 (2016–02–08) it will work just fine! Wouldn’t it be nice if we could write code using the features that we want, without having to worry about compatibility with browsers? Enter Babel.

Babel is, according to their words, a “JavaScript compiler”, in the sense that it transpiles and polyfills your code to ES5, making it compatible with any modern browser. But as always nothing like an example! First edit our src/index.js as follows:

import _ from 'lodash';
class Popup {
constructor(config = {}) {
this.capitalize = !!config.capitalize;
}
  alert(text) {
const output = this.capitalize ? _.capitalize(text) : text;
    window.alert(output); // eslint-disable-line no-alert
}
}
const popup = new Popup({ capitalize: true });
popup.alert('hello universe!');

So we refactored our code to have a class responsible for handling alerts, and also we changed the way we import lodash, nothing fancy or even required, but perfect for what we want to demonstrate. This code, like the previous Potato class sample, won’t work in certain browsers (you can try launching webpack-dev-server to check if it works on yours). So we’ll install Babel to help us, running the following command:

$ npm install babel-cli babel-preset-es2015 --save-dev

As the name implies this installs Babel’s CLI and the preset for ES2015/ES6. Babel works via plugins (and a preset is just a collection of plugins), meaning that it won’t do anything unless configured with said plugins/presets. Let’s test this by executing the command to compile our code:

$ node_modules/.bin/babel src/index.js

This will output the file exactly as is, which is not what we wanted at all. So we’ll configure babel by creating, at the root of our project, a file called .babelrc with the following content:

{
"presets": ["es2015"]
}

Now try running the compile command again, and it will output our code converted to ES5. Awesome! So we just need to add it to our bundling process. Fortunately, similar to ESLint, there’s a webpack loader for Babel, so let’s install it:

$ npm install babel-loader --save-dev

And configure webpack to use the loader, by adding babel-loader to the module configuration in webpack.config.js, as follows:

module: {
preLoaders: [
{
test: /\.js$/,
loader: 'eslint-loader',
exclude: /node_modules/
}
],
loaders: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
}
]
}

Let’s try it out! Start your webpack-dev-server (or restart it if it’s already running, so that the new configuration takes effect) and try opening your page. It now works on both browsers that I mentioned previously!

This will be it for today, but it goes without saying that Babel can do much more! For example, Facebook deprecated their own custom tool to compile JSX in favor of Babel. So definitely head over to Babel user handbook page to read more about Babel!

As always the code is available here.

Thanks for reading!

PS: Part 6 is up!