Getting acquainted with Browserify

This weekend I decided I’d take a deep dive and immerse myself in a tool called Browserify.
Browserify allows you to bundle up Node-JS modules that can be executed in the browser environment. This enables what is commonly referred to as isomorphic JavaScript, or more recently universal JavaScript — where the same code can execute in both the server and the browser.

 

##Why is Browserify useful? The lack of modularisation in JavaScript is something that has plagued developers for the past two decades. Without a module system it becomes increasingly arduous to manage large applications, especially with JavaScript’s dependency on the global scope. Browserify allows us to use Node’s module system, but within the browser environment.

Before we go any further into Browserify we need to do a little ground work to ensure we have a least a basic understanding of Node and NPM.

 

##Node Node is a server-side JavaScript environment that runs in Google Chrome’s highly optimised V8 engine. This post won’t go into great detail about Node, but two important aspects of Node that can really help us with code organisation are NPM and Modules.

###NPM NPM is a synonym for Node Package Manager, it is now the world’s most popular programming ecosystem, allowing developers to publish, share code and manage project dependencies. Assuming you have Node installed on your machine, you must initialise NPM in your project’s root using the command:

    npm init

You should then follow the instructions as you are prompted, giving your project a name, license, linking to a GIT repository and so forth.
This process will generate a package.json file – you can think of it like a global settings file that NPM is able to reference. As you install dependencies they will stored inside of a folder named node_modules Your dependencies will likely contain their own node_modules folder too, containing their dependencies. NPM will cleverly recurse down the tree and load in all of the required assets to run a module. It’s not something you ever have to worry about, and is one of NPM’s best features.

You can install dependences and publish modules via the command line. An example to install Lodash as a dependency would be:

    npm i --save lodash

The i is shorthand for install and the --save flag tells NPM to make a reference to this dependency in the package.json file. If you open up your package.json file now it should read something like this:

{
  "name": "myProject",
  "description": "myDescription",
  "version": "0.1.0",
  "author": "Robert Smith",
  "url": "http://rbrtsmith.com",
  "license": "ISC",
  "dependencies": {
    "lodash": "^3.10.1"
  }
}

Note that Lodash has now been added as a dependency - The numbers represent the version number using semantic versioning. You can explicitly choose which version of a package you want to install with the -v flag followed by the version number.

So what is the reason we add our modules as project dependencies? The reason is to allow us to publish our projects to remote repositories which will allow for collaboration and sharing without polluting the environment with all of our dependencies.
The package.json file can be read by NPM to fetch all of the required packages from NPM with the following command.

    npm i

Pretty neat huh? That’s NPM in a (brief) nutshell. We will come back to package.json a little later as it has a few more tricks up it’s sleeve that happen to be especially useful for running tools like Browserify.

###Modules Node ships with a module system known as Common JS Common JS modules allow us to import both modules fetched from NPM and our own locally created modules into our project. We can import files via the require statement:

//main.js
    var _ = require('lodash');

The lodash function will then be assigned to the underscore character. Note - the _ character has no special meaning, it is a valid variable name just like $ is. There’s no need to specify a path for the module as Node instinctively knows to look inside the node_modules folder for the module.
Our module is likely to have it’s own require statements to pull in it’s own dependencies from it’s own node_modules folder.
This whole process completes recursively - it’s not something you need to ever concern yourself with, such is the brilliance of NPM.

The require method is slightly different if we are to pull in our own local dependencies, say we had a function named multiply that we wanted to pull in we could do so with the following:

//main.js
    var multiply = require('./multiply');
    console.log(multiply(5,10));

Where the dot represents the current directory.

In order to create a module we have to use the exports function. We will do this with our multiply function:

//multiply.js
    module.exports = function(a,b) {
        return a * b;
    };

Our file structure should look a little something like this:

    /project
    |--main.js
    |--multiply.js
    |--package.json
    |--node_modules
        |--lodash
            |--array.js
            |--chain.js
            |--collection.js
            |....

Using Node we can execute our program:

    node main.js // 50

The value of the value returned from our multiply function will get logged to the console.

However if we tried to run this directly in the browser we will get the following reference error: Uncaught ReferenceError: require is not defined As mentioned earlier, the browser (At the time of writing) does not have a module system such as require. This will gradually change as browsers implement ES6 modules. In the meantime we can use a tool like Browserify to bundle up these modules into a file that can be executed in the browser.

 

##Browserify Let’s install browserify into our project as a dependency using NPM

    npm i --save browserify

and now our package.json will look something like this:

{
  "name": "myProject",
  "description": "myDescription",
  "version": "0.1.0",
  "author": "Robert Smith",
  "url": "http://rbrtsmith.com",
  "license": "ISC",
  "dependencies": {
    "lodash": "^3.10.1",
    "browserify": "^11.1.0",
  }
}

Now Browserify is installed we can run it from our CLI and use it to bundle our modules into a file for the browser, we’ll call it bundle.js

    browserify main.js >  bundle.js

if you now open up bundle.js you will see the output file the Browserify has generated. If you load this file into the browser:

<script src="bundle.js"></script>

.. and open up the console you will see the result of calling the multiply function. Let’s import jquery to our project..

    npm i --save jquery

Then we can require jQuery and use it to output our result to the DOM:

var multiply = require('./multiply');
var $ = require('jquery');

$(document.body).html(multiply(10,5));

refresh your page and you will see 50 get logged to the browser. Pretty neat.

By now I hope you’re beginning to see the usefulness of Browserify and NPM, we can very quickly pull down any dependencies and serve them up, without having to really worry about scopes, namespacing or any of that.

Of course we can do much more with Browserify, we can use the ´-d´ flag to specify a sourcemap for debugging.

    browserify main.js >  bundle.js -d

We can install plugins for Browserify such as Watchify which watches for changes in required files, Babelify which allows us to use ES6, transpiling it into ES5 compatible code before piping which it then pipes to Browserify.

They are the plugins that I’ve tried so far, and the command to run it all is getting a little verbose:

    watchify main.js -t babelify -o bundle.js -d

Fortunately Node has another feature that can help us out here.

 

##Scripts In our package.json we can declare scripts or commands that can aliased to something a little more sensible. For example I will show a package.json with the command highlighted in the previous section aliased to ‘watch’. We can also see the recently installed dependencies

    {
      "name": "myProject",
      "description": "myDescription",
      "version": "0.1.0",
      "scripts": {
        "watch": "watchify main.js -t babelify -o bundle.js -d"
      },
      "author": "Robert Smith",
      "url": "http://rbrtsmith.com",
      "license": "ISC",
      "dependencies": {
        "babelify": "^6.3.0",
        "browserify": "^11.1.0",
        "jquery": "^2.1.4",
        "lodash": "^3.10.1",
        "watchify": "^3.4.0"
      }
    }

Now to execute the script/command we can use npm run plus the script name

    npm run watch

You can add any number of scripts to your package.json, and they’re not restricted to Browserify. They can be used to execute any bash script / command but are typically used for Node related tasks that are commonly executed.

 

##Final words Although this post doesn’t really give any examples of universal JavaScript you should be able to see how you could for example write some data validation that could execute in the client and the server.
This is useful for two reasons:

  1. There’s no context switching between languages with JavaScript used on both ends.
  2. Code reuse - universal JavaScript is DRYer and now there’s only a single validation module to maintain, the benefits of that should be quite clear.

You can find the repository for the example used in this article here

We’re only really scratching the surface here of what is possible with Browserify, It can be combined with a task runner such as Gulp so you can use Gulp to run Browserify along with other tasks such as Sass Compilation, Bundle minfication and many other things.
I talk about Gulp in my previous post A modern frontend workflow

Browserify also isn’t the only module system, more recently Webpack has been gaining traction within the community and is a viable alternative to Browserify.

I should also mention that in future posts I will be gradually introducing ES6 code into my examples. Some may find it harder to follow, but ES6 is now an official standard that we all must learn at some point. I believe that point is now. I also don’t like the idea of my posts going quickly out of date. So from here on out — It’s time to embrace ES6