ES6 with Babel.js

ES6 with Babel.js

babel_meme

With Babel.js, we can all use ES6 before browsers support it

ECMAScript 2015, also commonly known as ES2015 or ES6, is the specification that defines the ECMAScript language, of which JavaScript is one implementation. This new version of the specification introduces language features to JavaScript that can improve developer efficiency and happiness.

Some features of the ES6 spec have already been implemented in browsers, whilst others are only beginning to be implemented. However if your desired features are not implemented yet, or you need to support older browsers, it is still possible to get the benefits of ES6 now by using Babel.js.

Over the last few months we have been using Babel to gain access ES6 features, while still maintaining support for browsers like Internet Explorer 9. In this blog post I will explain what Babel is, and how you can use Babel for yourself.

What is Babel?

Babel is a JavaScript transpiler, also known as a source-to-source compiler. It converts JavaScript code with ES6 language features to equivalent code that uses only language features from the widely-supported ES5 specification.

This transpiled source code can then be run in any browser that supports ES5, for example, Internet Explorer 9+, Chrome 23+, Firefox 21+, Safari 6+ (ECMAScript 5 Compatibility Table).

The result is that we can all benefit from the new ES6 syntax right now as long as we meet these reasonable browser requirements. Even failing these browser requirements, another approach could be to include es5-shim.js and patch in the required ES5 features.

ES6 Features

I’m not going to go into much depth on the new language features and syntax that ES6 brings to JavaScript, but a quick overview will help illustrate the power of Babel.

Babel provides the following new language features straight out of the box:

  • Arrow functions using =>,
  • let,
  • const,
  • Classes,
  • Template strings,
  • Destructuring,
  • Spread operator

The following new features are supported but require including the Babel polyfill:

  • Promises,
  • Generators,
  • Iterators,
  • Data structures – Map, Set, WeakMap, and WeakSet.

Babel also has great support for ES6 Modules by allowing you to compile your ES6 Modules into the module system of your choice. Babel supports compilation to CommonJS, AMD, SystemJS, and UMD module formats and also allows custom module definitions.

Using Babel

Babel provides a large number of options when it comes to integrating it into your current workflow. There are Babel plugins for all major front-end build systems including Grunt, Gulp, Webpack, Broccoli, Browserify, and more. If you are already using one of these build systems for tasks such linting, testing, and minification, Babel can easily slot into this build process. In this case it will probably be the least amount of effort to setup ES6 transpiling.

Other options include:

  • A require hook for Node.js environments so that Babel can automatically transpile required files,
  • Connect.js middleware for transpilation of static assets,
  • Command line tool for manual transpilation,
  • Automatic integration with the Ember, Meteor, and Rails frameworks.

Setting Up Babel With Grunt

We have been using Babel across two AngularJS applications for the past few months, and have integrated it into the our Grunt-based JavaScript build pipeline. Babel provides a grunt-babel plugin which we can use to setup Grunt tasks for ES6 transpilation.

To start using Babel with Grunt we need to make sure that we have the Grunt CLI installed globally, and Grunt and the grunt-babel plugin are installed in our project. We can install these using npm:

npm install -g grunt-cli
npm install grunt grunt-babel --save-dev

The next step is to setup the Grunt task for Babel that will transpile all of our ES6 JavaScript to ES5. To easily differentiate between JavaScript files that are using ES6 features (and therefore require processing by our Grunt task) and those that do not, we have been following the practice of using an .es6 file extension. We will therefore base our Grunt on transpiling *.es6 files to *.js.

Assuming that we have a basic Gruntfile.js setup (see Grunt – Getting Started if this is not the case) we can add the Babel task:

module.exports = function (grunt) {

  require('load-grunt-tasks')(grunt);

  grunt.initConfig({
    // Other grunt tasks
    // ...

    babel: {
        es6: {
            files: [
                {
                    expand: true,
                    src: ['app/scripts/**/*.es6'],
                    ext: '.js'
                }
            ]
        }
    }
  });
}

This Grunt task will process all .es6 files, including those in nested directories, under app/scripts and produce transpiled versions of the same name and in the same location as the originals, but with the .js extension. These transpiled versions can then be further processed by minification and other build tasks.

Another approach could be to have the Babel Grunt tasks produce a single file which is the concatenation of all the .es6 files after compilation, but we prefer the former approach so that we can run our local development using the non-concatenated .js for easier debugging.

Once we have set up the Babel Grunt task we can add it to any custom Grunt tasks we have created. For example we have a build task that handles concatenation, minification and other processes to get the JavaScript code ready for production environments:

  grunt.registerTask('build', [
    'clean:dist',
    'wiredep',
    'ngconstant:dist',
    'useminPrepare',
    'concurrent:dist',
    'babel:es6',
    'autoprefixer',
    'concat',
    'ng-annotate',
    'copy:dist',
    'cdnify',
    'cssmin',
    'uglify',
    'filerev',
    'usemin',
    'htmlmin'
  ]);

If you are using Grunt’s serve task to run your JavaScript application for local development, you can hook into Grunt’s watch task to provide automatic transpilation of .es6 files as soon as they change. Along with livereload, this can help improve the productivity of your development. This is as easy as adding a Babel task into the watch task configuration and specifying the files that you want to watch for changes:

  watch: {
    babel: {
      files: ['app/scripts/**/*.es6'],
      tasks: ['babel']
    }
  }

Once Babel is integrated into the development build process, we can start seeing the benefits of the new language features straight away. Just rename existing .js files to .es6 and start including ES6 syntax, or use .es6 for any new JavaScript code you write. We can add as little or as much ES6 syntax as is needed, and new ES6 features can be of great benefit in refactoring older JavaScript code.

Tips and Traps

If you are following the practice of including "use strict"; in your JavaScript, you will quickly find out (as we did) that Babel has a built in strict-mode transformer that will automatically prepend this directive to all files processed by Babel. This can result in duplicate strict mode directives that can clutter your code. To handle this either strip the "use strict"; statements from .es6 files, or Babel has the option to disable certain transformers. In Grunt this is achieved by using the blacklist option:

  babel: {
    es6: {
      options: {
        blacklist: ['strict']
      },
      files: [
        ...
      ]
    }
  }

Babel also provides a number of optional utility transformers which are unrelated to ES6, but which provide useful functionality. This includes minification tasks such as dead code elimination and removing console.* functions. This might be functionality that already exists in your build process, but give you may the opportunity to consolidate them into a single build step. In Grunt these options transformers can be activated using:

  babel: {
    es6: {
      options: {
        optional: ['minification.deadCodeElimination']
      },
      files: [
        ...
      ]
    }
  }

Following our approach of transpiling .es6 files to .js of the same name presents a risk that developers will work in the .js file without realising that it has been automatically generated from the .es6 version. To combat this, we have added an additional step in the build process where a comment stating “Autogenerated from .es6 file, do not edit” along with a time stamp is prepended to the generated .js files. This helps to serve as a reminder not to modify these files, especially on older projects where not all JavaScript files will be generated from .es6 files.

What’s Ahead For Babel

Even after all ES6 features have been implemented in browsers and the need to support browsers without ES6 disappears, the story won’t end for Babel. Babel’s goal is to be a transpiler for all future versions of JavaScript, not just ES6. Consequently, new features will be included as they enter the proposal stage.

Babel currently has experimental support for 9 features of the ES7 specification, although these features are subject to varying levels of change as the proposals are stabilised. This means Babel will continue to provide developers great benefit for a long time to come.

Tags:
, ,
2 Comments
  • Artem Dulebov
    Posted at 01:12h, 24 October Reply

    Thanks a lot, that is very helpful.

  • h1944091
    Posted at 09:04h, 05 October Reply

    Thanks for this, very useful.

Leave a Reply

Discover more from Shine Solutions Group

Subscribe now to keep reading and get access to the full archive.

Continue reading