Browserify

It is common to organize the code in several modules when we are developing Javascript applications. In Node.js ecosystem, we can import a module with the require() function and export symbols by adding them to the module.exports object. On the other hand, ES2015 adds import statements and export keywords. But unfortunately, both of these techniques are not supported by any browsers. To deploy our Javascript applications through browsers, we have to bundle our Javascript source code with Browserify in advance.

Bundling Modules into One File

We can install Browserify with:

$ npm install -g browserify

And then, we can bundle Javascript source files with:

$ browserify -o [output.js] [mainapp.js]

Example

In this example, we separated our code into three modules: utils.js, posts.js, and app.js, and we would like to bundle them into one output.js.

This is the content of utils.js:

function findMin(array, lessThan) {
    return Array.prototype.reduce.call(array, function (a, b) {
        return lessThan(a, b) ? a : b;
    });
}

function findMax(array, lessThan) {
    return Array.prototype.reduce.call(array, function (a, b) {
        return lessThan(a, b) ? b : a;
    });
};

exports.findMin = findMin;
exports.findMax = findMax;

This is the content of posts.js:

function Post(title, numVisited) {
    this.title = title;
    this.numVisited = numVisited;
}

Post.prototype.toString = function () {
    return this.title;
};

function compareByTitle(a, b) {
    return (a.title < b.title);
}

function compareByNumVisited(a, b) {
    return (a.numVisited < b.numVisited);
}

exports.Post = Post;
exports.compareByTitle = compareByTitle;
exports.compareByNumVisited = compareByNumVisited;

This is the content of app.js:

var posts = require('./posts'),
    Post = posts.Post,
    compareByNumVisited = posts.compareByNumVisited,
    compareByTitle = posts.compareByTitle;

var utils = require('./utils'),
    findMin = utils.findMin,
    findMax = utils.findMax;

var array = [
    new Post('b', 3),
    new Post('c', 1),
    new Post('a', 2),
    new Post('d', 5),
    new Post('e', 4),
];

var leastPopular = findMin(array, compareByNumVisited);
var mostPopular = findMax(array, compareByNumVisited);
console.log('Least Popular:', leastPopular.toString());
console.log('Most Popular:', mostPopular.toString());

var minTitle = findMin(array, compareByTitle);
var maxTitle = findMax(array, compareByTitle);
console.log('First in Alphabetical Order:', minTitle.toString());
console.log('Last in Alphabetical Order:', maxTitle.toString());

Now, we can bundle Javascript source files with:

$ browserify -o output.js app.js

Then, we can run output.js with:

$ node output.js
Least Popular: c
Most Popular: d
First in Alphabetical Order: a
Last in Alphabetical Order: e

We can also create index.html to include output.js and test the bundled output in the browser:

<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8" />
    <title>Test</title>
    <script type="text/javascript" src="output.js"></script>
  </head>
</html>

Source Map

Bundling several Javascript modules into one makes it more difficult to debug. A developer has to spend time finding the corresponding module. Source Map was created to map the processed Javascript file back to their source Javascript files. To generate source map with browserify, specify -d option:

$ browserify -d -o output.js app.js

And then, open the debugger in your favorite browser (remember to enable source map support in your browser.)

For example, if you add undefined to the end of array, then you will see the differece:

var array = [
    new Post('b', 3),
    new Post('c', 1),
    new Post('a', 2),
    new Post('d', 5),
    new Post('e', 4),
    undefined,  // CHANGED
];

ECMAScript 2015

To bundle ECMAScript 2015 source files, we have to transform them with babelify (the Babel transpiler integration).

First, we have to install babelify and babel-preset-es2015:

$ npm install -g browserify babelify babel-preset-es2015

Second, pass extra -t option when we are bundling source files:

$ browserify -o output.js -t [ babelify --presets [ es2015 ] ] app.js

For example, here is the content of utils.js (using ES2015):

export function findMin(array, lessThan) {
    return Array.prototype.reduce.call(array, function (a, b) {
        return lessThan(a, b) ? a : b;
    });
}

export function findMax(array, lessThan) {
    return Array.prototype.reduce.call(array, function (a, b) {
        return lessThan(a, b) ? b : a;
    });
};

This is the content of posts.js (using ES2015):

export function Post(title, numVisited) {
    this.title = title;
    this.numVisited = numVisited;
}

Post.prototype.toString = function () {
    return this.title;
};

export function compareByTitle(a, b) {
    return (a.title < b.title);
}

export function compareByNumVisited(a, b) {
    return (a.numVisited < b.numVisited);
}

This is the content of app.js (using ES2015):

import {Post, compareByNumVisited, compareByTitle} from './posts';
import {findMax, findMin} from './utils';

var array = [
    new Post('b', 3),
    new Post('c', 1),
    new Post('a', 2),
    new Post('d', 5),
    new Post('e', 4),
];

var leastPopular = findMin(array, compareByNumVisited);
var mostPopular = findMax(array, compareByNumVisited);
console.log('Least Popular:', leastPopular.toString());
console.log('Most Popular:', mostPopular.toString());

var minTitle = findMin(array, compareByTitle);
var maxTitle = findMax(array, compareByTitle);
console.log('First in Alphabetical Order:', minTitle.toString());
console.log('Last in Alp`habetical Order:', maxTitle.toString());

Bundle source files with browserify command and babelify:

$ browserify -o output.js -t [ babelify --presets [ es2015 ] ] app.js

Finally, run the output script:

$ node output.js
Least Popular: c
Most Popular: d
First in Alphabetical Order: a
Last in Alphabetical Order: e

Epilogue

In this post, we introduced Browserify which is able to bundle multiple Javascript source files into one output file. We also mentioned the concept of source map and ES2015 transformation. Hope you enjoy this article.