Modular JavaScript with Browserify

19th January 2014

In an effort to write more articles, I will be writing more about libraries, tools and cool stuff that I have tried out recently. One of those things is Browserify, over the holidays I decided to start a HTML5 game development course, I thought this would be a great opportunity to also try out browserify and I found it to be a great way to modularise my code. This article will cover installation and getting started with writing modular front-end code through browserify.

Browserify provides a method of organising your front-end javascript into re-usable modules. It follows the same style as node.js modules and provides browser shims for a lot of node's core library, it also allows npm modules to be required and used on the browser side.

All code for this article is available at: github.com/petecoop/browserify-article-code

  • Install node, this will come with npm
  • npm install -g browserify

I'll start off by going through the basics of how the node module system works, if you're already familiar with this you might want to skip this section.

To explain the node module system I've created the following:

main.js

var maths = require('./mymodule');
var User = require('./User');
 
var num = maths.multiply(1, 2);
 
var someUser = new User('Pete');
var welcomeMessage = someUser.welcome();

mymodule.js

exports.multiply = function (ab) {
  return a * b;
};

User.js

module.exports = User = function (name) {
  this.name = name;
};
 
User.prototype.welcome = function () {
  return 'Welcome ' + this.name;
};

In this basic example I've demonstrated the use of require and exports.

The require() function is used to load in modules, the ./ indicates that the module is loaded from the current directory, you might also notice that you can leave out the .js file extension. To load in modules from node's core or from modules installed through npm simply use require('module-name') and the module system will automatically find and load in the specified module.

require() will return an object of all exported properties of the module and in my example is returned to var maths before use.

To expose properties from within your module you can add to the exports object. In my example mymodule.js uses the exports object to expose it's multiply function.

Using the exports object allows you to build your module one property at a time, however if you would like to export a complete object you can use module.exports. In my example I've created the User module to demonstrate the use of module.exports to export a complete object.

That about covers the basics of node modules, if you would like to read up on it check out the documentation.

Browserify bundles all of your modules together into one javascript file by running:

browserify main.js -o bundle.js

This will automatically load in anything required within main.js and output the bundled javascript to bundle.js

If like me you like your automated build tools, you can try out the grunt-browserify Grunt Task - which I've had some success with.

You can alternatively try watchify which was built specifically for browserify.

Now I've gone through the installation and explanation of how the module system works, I thought it would give a better example of how to build an application with browserify if I actually built one.

I'm going to create a basic weather app that allows the user to enter a location and using an API recieve weather results for that location.

I'll be using the Open Weather Map API

To start with I'll create an index.html:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Weather App</title>
</head>
<body>
  <form id="locationForm">
    Enter a location:
    <input id="location" type="text">
  </form>
  <div id="output"></div>
  <script src="bundle.js"></script> 
</body>
</html>

Nothing special here, I've just created a form with an input and gave id's to each of them so I can easily target them with my javascript. The plan is to hook into the onsubmit event of the form, then get the value from the input, make a request to the weather API and display some results in the output div.

I'll now create my main.js:

var weather = require('./weather');
 
var form = document.getElementById('locationForm');
form.onsubmit = function (e) {
  var location = document.getElementById('location').value;
  weather.get(location, function (data) {
    var output = '<h1>' + data.name + '' + data.sys.country + '</h1>';
    output += '<p>Temp(&deg;C): ' + data.main.temp + '</p>';
    output += '<p>' + data.weather[0].description + '</p>';
    var element = document.getElementById('output');
    element.innerHTML = output;
  });
  return false;
};

As you can see I've already required the weather module, which I will create next. I've hooked into the form's submit event and grabbed the value from the input, I'm then sending this to weather.get which I plan on taking the location as it's first argument and a callback with the data I need as it's second. I'll then format this data into HTML and put it in my output div.

weather.js

var jsonp = require('./jsonp');
 
var url = 'http://api.openweathermap.org/data/2.5/weather?units=metric&callback=jsonpCallback&q=';
 
exports.get = function (citydone) {
  jsonp(url + city, done);
};

I was going to use this as an opportunity to use the core http module, but as this is a cross domain request I've had to create a jsonp module - this is a good example of a tiny re-usable module.

module.exports = function (urldone) {
  var script = document.createElement('script');
  script.type = 'text/javascript';
  script.src = url;
  var s = document.getElementsByTagName('script')[0];
  s.parentNode.insertBefore(script, s);
  window.jsonpCallback = done;
};

Once all this is done I bundle it:

browserify main.js -o output.js

And that's it! A nice little app to get weather based on the location you enter.

Okay so you've read the whole article, but still don't get the benefits of using browserify, here's a few points.

Keep your application modular, it will be a lot easier when it comes to testing/debugging especially when creating a large application.

Your modules don't have to be application specific, you can create modules that you re-use in other app's. You can publish them to npm to share them with the world and for easily installing in future projects.

You can also re-use them within your server-side node.js applications, and even write modules that are used on both ends.

There is already loads of npm modules and a lot of them are likely to work within the browser too.

Although large libraries e.g. jQuery have a lot to offer, you often end up using a small amount of the whole thing which means that a large part of the library is loaded onto the client for no reason.

Using browserify and modular code you can use modules that are good at individual things rather than being an all-in-one solution.

If you insist on using something like jQuery see if it's available on npm and if it's compatible with browserify, often people will wrap libraries into browserify-compatible modules. If it's available then require it like any other module and let it benefit from any other modular code.