JavaScript
Article

Setting up an ES6 Project Using Babel and Browserify

By Ritesh Kumar

The JavaScript world is changing and ES6 is rapidly taking over. Many famous frameworks like AngularJS 2 and React Native have already started supporting ES6. It’s important that we are prepared for this change. To do so, we need to start writing code that uses ES6 even before the support for it lands in all browsers.

In this article, I’ll show you how to set up a project that integrates Babel and Browserify to write modern code that can be executed by older browsers as well. Babel compiles ES6 code into ES5 which is supported by many browsers, including old ones like Internet Explorer 9. Browserify is a tool for writing code that follows the CommonJS pattern and packaging it to be used in the browser.

Creating the package.json File

First of all, let’s see the folder structure of the demo we are going to make

/
|--dist/
   |-----modules.js
|--modules/
   |-----import.js
   |-----index.js
|--Gruntfile.js
|--package.json

In the project’s root folder, there are two files Gruntfile.js and package.json and two folders modules and dist. The modules folder contains all the modules written in ES6 and the dist folder contains the bundled and compiled ES5 JavaScript file. I have excluded .gitignore as it is just a utility file which in no way affects the project.

Now, let’s start by creating the package.json file. There are many fields in a typical package.json file like description, version, author, and others, but in this project we’re only using the important ones.

The following is the content of the package.json file we’ll use:

{
    "name": "browserify-babel-demo",
    "main": "dist/module.js",
    "devDependencies": {
        "grunt": "^0.4.5",
        "babelify": "^6.1.0",
        "grunt-browserify": "^3.8.0",
        "grunt-contrib-watch": "^0.6.1"
    }
}

As you can see from the file above, the modules used for this project are:

  • Grunt : A JavaScript task runner
  • grunt-browserify : The Browserify Grunt task
  • babelify : Babel transformer for Browserify
  • grunt-contrib-watch : A Grunt task to watch the JavaScript files for every change and then optionally execute tasks. In our case, we’ll run the browserify task on each change

All these modules are devDependencies as they are only needed in the development environment and not when the client-side code is executed. The versions of the modules can be set according to need.

Now run npm install in the root folder of the project to install all the dependencies listed in the package.json file. In case you’re not familiar with npm, I suggest you to read this article to get started with it.

Set up the Gruntfile.js

In this article I assume that you know what Grunt and a Gruntfile.js file are and how to work with Grunt. In case you need a refresher, I suggest you to go through this article before moving forward.

The JavaScript files containing code written in ES6 can have either .js or .es6 extension. Here for simplification purposes, we are using the .js extension for all the JavaScript files (even for those written in ES6). The code written in Gruntfile.js is as shown below:

module.exports = function (grunt) {
   grunt.initConfig({
      browserify: {
         dist: {
            options: {
               transform: [
                  ["babelify", {
                     loose: "all"
                  }]
               ]
            },
            files: {
               // if the source file has an extension of es6 then
               // we change the name of the source file accordingly.
               // The result file's extension is always .js
               "./dist/module.js": ["./modules/index.js"]
            }
         }
      },
      watch: {
         scripts: {
            files: ["./modules/*.js"],
            tasks: ["browserify"]
         }
      }
   });

   grunt.loadNpmTasks("grunt-browserify");
   grunt.loadNpmTasks("grunt-contrib-watch");

   grunt.registerTask("default", ["watch"]);
   grunt.registerTask("build", ["browserify"]);
};

We have defined two Grunt tasks:

  1. grunt default /grunt: When we run this command on the terminal inside the project folder, this task starts watching all the JavaScript files included in the modules folder. For any change detected, Grunt will execute the browserify task. The watch task keeps running until the task is terminated. To terminate the task press Ctrl + C on the terminal.
  2. grunt build: This task executes the browserify task once and stops.

Every time the browserify task executes, all the JavaScript code present inside the modules folder is bundled into a single JavaScript file. Then the code goes through babelify (Babel transformer for Browserify) which compiles that bundled ES6 code into ES5 code.

As seen in the above code, we have set loose: 'all' as an option for babelify as we want the ES5 code to be as close to the ES6 code that we are writing as possible. We don’t want it to adhere strictly to the specification because this will be more difficult for an ES6 beginner to debug. All the other options provided by Babel can be found here.

Let’s Write Some ES6 Code

This demo uses only a few features of ES6, such as import and export. So, if you want to have a deep dive into ES6, I suggest you to go through the ES6 tutorials published here on SitePoint. You’ll get an idea of all the new and exciting features that ES6 will bring to the table.

In our demo we’ll create two files, index.js and import.js, inside the modules folder. The former is the main file of the project, while the latter contains all the functions and variables that are part of a module. In other words, index.js will import all the functions and variables from the import.js file.

The code of the import.js file is listed below:

var sum = (a, b = 6) => (a + b);

var square = (b) => {
    return b * b;
};

var variable = 8;

class MyClass {
    constructor(credentials) {
        this.name = credentials.name;
        this.enrollmentNo = credentials.enrollmentNo
    }
    getName() {
        return this.name;
    }
}

export { sum, square, variable, MyClass };

The import.js file is a module that contains a variable, a class, and function expressions (written using the arrow function). The functions and the variables defined in a module are not visible outside of the module unless we explicitly export them. You can do that by using the export keyword. In the last line of import.js, we have exported sum, square, variable and MyClass.

In the index.js file we import all the variables of the module by using the import keyword. So, all these imported variables from import.js file become accessible in the main file, i.e. index.js. In the code below, which lists the content of the file index.js, you can see how we are able to use the square() function or MyClass by importing the module that exports it. We can import functions, variables, and classes from as many files as we want.

import {sum, square, variable, MyClass} from './import';

// 25
console.log(square(5));

var cred = {
    name: 'Ritesh Kumar',
    enrollmentNo: 11115078
}

var x = new MyClass(cred);

//Ritesh Kumar
console.log(x.getName());

In case we are importing from a file that has a .es6 extension then we have to write the filename with the extension in import. An example is shown in in the code snippet below:

// if file extension of the importing file is .js
// both of the following methods work
import { sum, square, variable, MyClass } from './import';
import { sum, square, variable, MyClass } from './import.js'

// if file extension of the importing file is .es6
// its mandatory to add the extension
import { sum, square, variable, MyClass } from './import.es6';

Since we are using Browserify, we can also import modules using the CommonJS pattern by using the require() method. For example, if we want to import jQuery as a module, we can use the following code:

var $ = require('path/to/jquery');
$(window).click(function(){
	//do something
});

Babel can convert ES6 code to ES5, but it can’t bundle the modules. So, we are using Browserify for bundling the modules.

The power of ES6’s import and export combined with the require() method, gives us the freedom to organize all of the client-side code into modules and at the same time write the code using all the power of the new version of JavaScript.

As soon as we run the grunt command on the terminal a few things will happen:

  • Browserify will bundle all the files into one
  • The bundled file is passed through babelify to transform the code into ES5
  • A file named module.js that can be executed in all modern browsers, including Internet Explorer 9, is generated

To give you an idea of what the generated module.js file looks like, I’m including the resulting code below:

(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
"use strict";

exports.__esModule = true;

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var sum = function sum(a) {
    var b = arguments[1] === undefined ? 6 : arguments[1];
    return a + b;
};

var square = function square(b) {
    "use strict";
    return b * b;
};

var variable = 8;

var MyClass = (function () {
    function MyClass(credentials) {
        _classCallCheck(this, MyClass);

        this.name = credentials.name;
        this.enrollmentNo = credentials.enrollmentNo;
    }

    MyClass.prototype.getName = function getName() {
        return this.name;
    };

    return MyClass;
})();

exports.sum = sum;
exports.square = square;
exports.variable = variable;
exports.MyClass = MyClass;

},{}],2:[function(require,module,exports){
'use strict';

var _import = require('./import');

console.log((0, _import.square)(5)); //25

var cred = {
    name: 'Ritesh Kumar',
    enrollmentNo: 11115078
};

var x = new _import.MyClass(cred);
console.log(x.getName());

},{"./import":1}]},{},[2]);

This file can be then be used in your web pages just as a normal JavaScript file. If you want, you can also use other Grunt tasks like grunt-uglify, grunt-rev, and many others on module.js. Once done, you’re ready to include module.js in the HTML page and the browser will load it.

<!-- Usage of the final bundled file in html -->
<script src="path/to/module.js"></script>

Conclusion

In this article we’ve seen how to write a project that has its JavaScript code written using the features introduced by ES6. In addition, I covered how to configure Browserify and Babel as Grunt tasks using grunt-browserify and babelify respectively. We created a demo project which demonstrated how this setup works and the way in which ES6 code is compiled into ES5.

I hope that you have enjoyed the article and I look forward to reading your comments. In case you want to play with this project, the code of the demo project is available here.

  • benS

    Nice article ! I’d like to see more article like that, helping setting up web project !

    • ritz078

      Glad you liked it .

  • bradleymeck

    add `-d` flag to browserify and `–source-maps` to babel for saner debugging.

    • Ritesh Kumar

      I avoided the options so that a beginner doesn’t gets confused. We can have a separate article on the debugging part.

      • Hugo Hase

        Yes please

      • StijnDeWitt

        Actually, I myself as a beginner with Browserify get confused because all the info is spread out. I would love to know what to add/change to the exact config shown in this post to add uglify and sourcemaps (so we get everything from debugging support to code minification). Everyone shows only pieces and bringing them together is hard.

  • Rafailong

    I think this methods work with Node.js project too, Am I right?
    Thanks for sharing! :)

    • Ritesh Kumar

      Yes it does.

  • hgoebl

    Good post, but unfortunately not with a good CSS for media print. I wanted to take a PDF with my vacations…

  • racedev

    “Babel compiles ES6 code into ES5 which is supported by many browsers, including old ones like Internet Explorer 9…”

    The compiled code (module.js) shows “use strict” in a few places. Does this really work in IE9? IE9 does not support strict mode.

  • Eddyson Tsai

    Sorry, Why run the grunt command , Runnig Watch task ,Running “watch” task

    ———————————————————————-
    Waiting…

    Verifying property watch exists in config…OK

    Verifying property watch.scripts.files exists in config…OK

    Watching modules/import.js for changes.

    Watching modules/index.js for changes.

    ———————————————————————-

    stop in here , and no result…

  • Sasha Burchuk

    Great little tutorial but I believe that ‘name’ is reserved, so perhaps use a different reference?

  • rollrodrig

    Nice tutorial, thank you.
    Do you know how optimize the compilation time?
    it takes 4 seconds :/
    and i just have two files to test -___-

  • Maxi Wu

    the best article that I came across about running ES6 on client-side. Babel 6 is here now, how does Babel 6 compare to babelify? is there a way to combine babel 6 and browserify?

  • Barnaby Jones

    After installing babel, the cli command is not found:
    npm babel script.js
    >error> babel:command not found

  • Clint Goodman

    Thanks for your article. We were struggling with how to figure out how to integrate both ES6 and browserify, and this article answered everything very quickly.

  • http://cv-victoraraya.tk/ Victor Araya Jiménez

    HI there, what do you recommend to compile Promise object for old browsers(IE), in this environment. maybe something like: https://www.npmjs.com/package/babel-plugin-es6-promise

    Thanks!

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in JavaScript, once a week, for free.