Browserify – modules for client side javascript

When building node applications, i.e. server side javascript, you quickly get used to separating code into different modules, and using them or other modules you’ll find with npm with the require statement.

var moduleX = require('moduleX');

There are plenty of good reason to separate different code parts from each other and wouldn’t it be great if one could do it the same way when building client side javascript apps as well? Unfortunately browsers don’t have a require method defined like node does. Relax, thanks to the awesome javascript tool Browserify you can continue to write code that uses the require method, even though your code will run in a browser. In this blog post I’ll give a short introduction to Browserify and then we’ll create a small app to demonstrate how to use it. browserify_logo

Quick intro to Browserify

The main purpose to use a tool like Browserify is that enables you to modularize your client side javascript code. You create small, separate modules with clear responsibility and instead of spaghetti code you usually get code that is well organized and easier to understand, reuse and test. Also, it gives you the possibility to use the many, many, many already existing modules on npm also in the browser. Browserify will most likely be run in node as a build step of your application. It will take all of your small javascript files (one per module), sort out all the dependencies and bundle them into one single file (which is the one you reference in your HTML file).

How to use Browserify

Let’s go ahead and try it out by creating a simple calculator app. But first we’ll have to install Browserify.

Installation

I assume you are familiar with Node.js and has its package manager npm installed. First we create a node project and a package.json:

npm init

Install Browserify:

npm install browserify -g

A module to add

Now it’s time to create our first module and save it in a file src/js/functions/add.js. This will be a module that can add two values and return the sum.

exports.calculate = function(x, y) {
    return x + y;
};

To expose the function to other modules in the application we simply add it as a property on the exports object. But hold your horses, what is this exports object and where did it come from? The exports object is what Browserify will give to other modules when they load this module. The code looks kind of empty right now but Browserify will wrap it in a function before it’s executed, so the final code will look like this:

function(require, module, exports) {
    exports.calculate = function(x, y) {
        return x + y;
    };
}

A module will behave like a singleton so if you want to have state in your module and let each user of the module get its own instance you should instead set an object as the exports property on the module variable:

module.exports = {
    calculate = function(x, y) {
       return x + y;
    }
}

A module to subtract

Lets create a second module and save it in a file src/js/functions/subtract.js. This will be a module than can subtract one value from another and return the difference.

exports.calculate = function(x, y) {
    return x - y;
};

A calculator module

Finally, lets create a calculator and save it in a file src/js/calculator.js. This will be the entry point of the calculator app and it will make use of the add and subtract modules to perform the actual calculations. It’s a super simple app that expects two input fields in the host HTML file (input1 and input2), two buttons (addButton and subtractButton) and a div where result is shown.

var add = require('./functions/add'),
    subtract = require('./functions/subtract'),
    $ = require('jquery');

function calculate(fn) {
    return function() {
        var value1 = Number($('#input1').val());
        var value2 = Number($('#input2').val());
        var result = fn(value1, value2); 
        $('#result').text(result);
    }
};

$(document).ready(function() {
    $('#addButton').click(calculator(add));
    $('#subtractButton').click(calculator(subtract));
});

First we require the add and subtract modules, but we also require jquery module to ease our DOM manipulation. You may notice the difference in syntax when a third-party module is required compared to a local module. When only a module name is provided to the require function Browserify will look for an npm installed package in node_modules folder. If you instead are looking for a local module you pass in the relative path to the file which holds the module, and without the file extension. ”.” represents the current directory and ”..” the parent directory. When page is loaded click handlers are attached to the buttons, and when a click event occurs the calculate function is called with the correct module and the simple math is performed. We must remember to install jquery to be able to require it:

npm install jquery --save-dev

Build with Browserify

The final step is to build this app using Browserify. It can be done on command line by passing in the entry point, the main file to be bundled, as the first argument and then flag -o to specify the output file.

browserify src/js/calculator.js -o public/js/bundle.js

When Browserify is done in a few milliseconds it’s possible to reference public/js/bundle.js from a HTML page and create a nice UI that uses the calculator. I’ll leave that to you since it’s ”out of scope” for this blog post. 🙂

Build with Gulp

It’s of course possible to use Browserify as a build step when using a build system like Gulp or Grunt. If you haven’t read my blog post about Gulp be sure to check it out later.

gulp.task('browserify', function () {
    var bundler = browserify({ 
        entries: './src/js/calculator.js'
    });
    return bundler
        .bundle()
        .pipe(source('bundle.js'))
        .pipe(gulp.dest('public/js'));
});

Additional things worth mentioning

Source maps

Since we now only have a single javascript file it can be pretty tricky to debug the code. It can however be solved by having Browserify generate a source map which maps our bundle.js back to the original calculator.js, add.js and subtract.js files. To do this provide the debug flag to Browserify on command line:

browserify src/js/calculator.js -o public/js/bundle.js --debug

Watchify

Watchify is a very helpful and time saving tool that will watch your source files for changes and re-run Browserify when a change is detected. To install it run:

npm install watchify -g

Now you can simply run watchify command instead of browserify command and it will re-run whenever the entry point javascript file or any or it’s required modules are changed.

watchify src/js/calculator.js -o public/js/bundle.js --debug

Or the Gulp way:

gulp.task('browserify', function () {
    var bundler = browserify({ 
        entries: './src/js/calculator.js'
    });
    bundler = watchify(bundler);
    return bundler
        .bundle()
        .pipe(source('bundle.js'))
        .pipe(gulp.dest('public/js'));
});

Transform

Transform is a way to extend Browserify’s functionality. By default Browserify expects a module like the ones we’ve written but transforms can be used to instead load CoffeeScript, Handlebars.js, React or something else. Lets have a look at how to use a React transform if our javascript contained React components. First, install reactify:

npm install reactify --save-dev

Then use flag -t to specify the transform Browserify should use at command line:

browserify src/js/calculator.js -o public/js/bundle.js --debug -t reactify

Gulp way:

gulp.task('browserify', function () {
    var bundler = browserify({ 
        entries: './src/js/calculator.js'
    });
    return bundler
        .transform(reactify)
        .bundle()
        .pipe(source('bundle.js'))
        .pipe(gulp.dest('public/js'));
});

Testing

Testing the add and subtract modules are pretty easy. I like Mocha as a test framework and Chai for assertions, so first install them:

npm install mocha -g
npm install chai --save-dev

Let’s add a test for the add function in test/addSpec.js:

var expect = require('chai').expect;
var add = require("../src/js/functions/add");

describe("add", function() {
    it("should return the sum of two numbers", function() {
        var result = add.calculate(5,5);
        expect(result).to.equal(10);
    });
});

Since node already has the require function defined we can require our module to test, write the spec and the run it from command line:

mocha

Unit testing a module with dependencies to other modules can be a little bit more trickier since one probably want to mock those dependencies and only test the current module. There are ways to solve this, and replace the dependencies with mocks, but I want go into that in this blog post. Check out proxyquire or rewire if you want to learn more about that.

Finally

Checkout the code at Github and a deployed version of the application.

Annonser

Kommentera

Fyll i dina uppgifter nedan eller klicka på en ikon för att logga in:

WordPress.com Logo

Du kommenterar med ditt WordPress.com-konto. Logga ut / Ändra )

Twitter-bild

Du kommenterar med ditt Twitter-konto. Logga ut / Ändra )

Facebook-foto

Du kommenterar med ditt Facebook-konto. Logga ut / Ändra )

Google+ photo

Du kommenterar med ditt Google+-konto. Logga ut / Ändra )

Ansluter till %s