We're live-coding on Twitch! Join us!
Getting Started with Browserify

Getting Started with Browserify


Browserify changed my life.

. . . My life as a Javascript developer, anyway. Unlike many of my peers--maybe most of them--I don't enjoy writing UIs. Hacking together client-side code always felt something like a visit to the dentist. I'm like a hobbit

Then Browserify happened. And everything changed.

With Browserify you can write code [in the browser] that uses require in the same way that you would use it in Node.

Browserify lets you use require in the browser, the same way you'd use it in Node. It's not just syntactic sugar for loading scripts on the client. It's a tool that brings all the resources NPM ecosystem off of the server, and into the client.

Simple, yet immensely powerful.

In this article, we'll take a look at:

  • What Browserify is & How it Works
  • Browserify vs Webpack
  • Building Your First Bundle
  • Browserify Transforms
  • Building a Useful Browserify Config
  • Integrating with Gulp

Before we get started, make sure you've got Node and NPM installed. I'm running Node 5.7.0 and NPM v3.6.0, but versioning shouldn't be a problem. Feel free to either grap the repo or code along.

Let's dive in.

better.dev Get Started w/ JavaScript for free!

Why Browserify?

Anyone who's worked with Node will be familiar with its CommonJS style require function.

require-ing a module exposes its public API to the file you required it in:

"use strict";
const React = require('react');

let Component = React.createClass ({
    /* Using React, save the world */

Node's require implementation makes modularizing server-side code quite a straightforward task. Install, require, hack: Dead simple.

Module loading in the client is an inherently different beast. In the simplest case, you load your modules in a series of <script> tags in your HTML. This is perfectly correct, but it can be problematic for two reasons:

  • It forces you to manage dependencies by ensuring your script tags appear in the proper order, and makes it cumbersome to manage complex dependency graphs
  • To quote Kyle Simpson's in the LAB.js documentation: "with regular <script> tags, you cannot control [script] loading and executing behavior reliably cross-browser."

The AMD specification and AMD loaders--Require.js being amongst the most popular--came about as solutions to these issues. And, frankly, they're awesome. There's nothing inherently wrong with Require.js, or AMD loaders in general, but the solutions furnished by newer tools like Browserify and Webpack bring distinct advantages over those offered by Require.js.

Amongst other things, Browserify:

  • Trivializes many preprocessing tasks with its transform system;
  • Solves the same problems regarding asynchronous loading addressed by Require.js;
  • Opens the doors to the vast and growing NPM ecosystem

We'll take a look at all of this and a whole lot more throughout the article. But first, what's the deal with Webpack?

Browserify vs Webpack

The religious wars between users of Angular and Ember, Grunt and Gulp, Browserify and Webpack, all prove the point: Choosing your development tools is serious business.

The choice between Browserify or Webpack depends largely on the tooling workflow you already have and the exigencies of your project. There are a number of differences between their feature sets, but the most important distinction, to my mind, is one of intent:

  • Browserify seeks to extend the Node ecosystem into to the browser. It only supports Node's flavor of the CommonJS require syntax, and provides browser-specific shims for much of Node's core functionality.
  • Webpack seeks to unify Javascript module syntaxes and provide tools for a full swath of static asset management tasks. It imposes no restrictions on your choice of module syntax, and offers full support for Javascript, CSS, and even image preprocessing.

If your project and dependencies are already closely tied to the Node ecosystem, Browserify is a solid choice. If you need more power to manage static assets than you can shake a script at, Webpack's your tool.

I tend to stick with Browserify, as I rarely find myself in need of Webpack's additional power. You mind find Webpack to be a solid choice if your build pipeline gets complex enough, though.

If you decide to check it out, take a look at Front-End Tooling Book's chapter on Webpack, and Pete Hunt's Webpack How-To before diving into the official docs.

Build Your First Bundle with Browserify

Note: If you don't feel like typing or copy/pasting, clone my repo.

Time to get our hands dirty. The first step is to install Browserify. Fire up a terminal and run:

npm install --global browserify

This installs the Browserify package, and makes it available system-wide.

Oh, and if you find yourself needing to use sudo for this, fix your NPM permissions.

Next, let's give our little project a home. Find a suitable place on your hard drive and make a new folder for it:

mkdir Browserify_Introduction && cd Browserify_Introduction

We'll need a minimal home page, as well. Drop this into index.html:

<!-- index.html -->
<!doctype html>
    <title>Getting Cozy with Browserify</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
      h1, p, div { text-align: center; }
      html       { background: #fffffe; }
    <div class="container">
      <h2>Welcome to the Client Side.</h2>

      <div class="well">
        <p>I see you've got some numbers. Why not let me see them?</p>

        <div id="response">
    <script src="main.js"></script>
    <script src="bundle.js"></script>

In the off chance you're typing this out by hand, you'll definitely have noticed the reference to the nonexistent main.js. Nonexistent files are no fun, so let's make it exist.

First, install Ramda:

npm install ramda --save

There's nothing special about Ramda, by the way. I just chose it because I like it. Any package would do.

Now, drop this into main.js:

"use strict";

var R = require('ramda');

var square = function square (x) { return x * x; }  
var squares = R.chain(square, [1, 2, 3, 4, 5]); 

document.getElementById('response').innerHTML = squares;

This is simple, but let's go step-by-step anyway.

  • Line 3 requires the Rambda library as R;
  • Line 5 defines a simple function for us to use in our example;
  • Line 6 uses Rambda to do some stuff, and assign the result to squares;
  • Line 8 finds the div on our page with the id response, and sets its innerHTML to squares

The important things to note are that we're using Node's require, available only in a Node environment, together with the DOM API, available only in the browser.

That shouldn't work. And, in fact, it doesn't. If you open index.html in your browser and open up the console, you'll find a ReferenceError just waiting to grab your attention.

Reference Error

Ew. Let's get rid of that.

In the same directory housing your main.js, run:

browserify main.js -o bundle.js

Now open up index.html again, and you should see our array of squares smack dab in the middle of the page.

It's that simple.

Under the Hood

When you tell Browserify to bundle up main.js, it scans the file, and takes note of all the files you require. It then includes the source of those files in the bundle, and repeats the process for its dependencies.

In other words, Browserify traverses the dependency graph, using your main.js as its entry point, and includes the source of every dependency it finds.

If you open up your bundle.js, you'll see this in action. At the top is some obfuscated weirdness; then, a portion with your source code; and finally, the entirety of the Ramda library.

Your Bundle

Magic, eh?

Let's take a look at some additional Browserify fundamentals.

Browserify Transforms

Browserify isn't limited to concatenating the source of your dependencies: It's also capable of transforming the code along the way.

"Transform" can mean many things. It can be compiling Coffeescript to Javascript, transpiling ES2015 to vanilla Javascript, or even replacing const with var declarations.

If it's a change to your code, it counts as a transformation. We'll take a look at using transforms in the full example, so hang on tight for usage details. For now, be sure to bookmark the growing list of available Browserify transforms for future reference.

Enabling Source Maps

One of the disadvantages to transformations--and builds in general--is mangled line references. When your code throws an error, you want the browser to tell you, take a look at line 57, column 23. Not, take a look at variable q on line 1, column 18,278 of main.min.js.

The solution is source maps. They're files that tell your browser how to translate between line references in your transformed code and line references in your original source.

With Browserify, enabling source maps is trivial. Run:

browserify --debug main.js -o bundle.js

The --debug flag tells Browserify to include source map information in bundle.js. That's all you have to add to make it work.

There is one downside to this, though: Adding source maps to bundle.js makes your bundle twice as large.

That's fine for development. But making your users download a file twice as big as the one they really need is a bit rude, don't you think?

The solution is to create two files: One for the source map, one for the bundle. If you're using Browserify alone, the tool of choice for this is exorcist.

Once you've installed it (npm install --global exorcist), you use it like this:

browserify main.js --debug | exorcist bundle.map.js > bundle.js

This rips all the source map information out of bundle.js and spits it into bundle.map.js instead.

That's mostly all there is to using exorcist. Be sure to check the exorcist documentation for the details.

Live Rebuild

I'll admit, it kind of sucks to have to drop out of your editor and into the CLI to rebuild your bundle every time you change your code.

. . . Good thing you don't have to.

There are a whole swath of tools for Browserify that keep an eye on your files and rebuild your bundle whenever they change. We'll take a look at two tools: Watchify, and Beefy.

Using Watchify

Watchify is a standard tool for automatically rebuilding your bundle.js whenever you update source files.

First, install it with NPM:

npm install --global watchify

Next, delete your bundle.js.

Now, navigate to your working directory in a new terminal, and run:

watchify main.js -o bundle.js -v

The -v flag tells Watchify to notify you whenever it rebuilds your bundle. It'll still work if you don't include it, but you won't be able to tell it's doing anything.

That aside, notice that using watchify is identical to using Browserify! You should have gotten some output, and if you check, you'll notice a newly updated bundle.js sitting in your working directory.

Now, open up main.js and save it without changing anything. You'll see Watchify rebuild your bundle and spit out some more logs--that's all it takes to automatically rebuild your bundle when you change your source!

The Watchify repo has all the information on more advanced usage, such as how to use it with exorcist. Check them out if you need.

If you ran the example, be sure to kill the Watchify process before moving on (just close the terminal you ran it in, or kill $(pgrep node) if you love you some CLI).


While it's cool that we can automatically rebuild our bundle when we change our source, it still kind of sucks to have to refresh the browser every time we want to see the changes.

Or maybe I'm just especially lazy.

Either way, Beefy makes it easy to enable live reload alongside automatic rebuild. It does two big things for you:

  • Spin up a local webserver that serves your files;
  • Start a process to watch your filesystem for changes to your source code.

Whenever you change anything, it rebuilds your bundle, and--if you tell it to--automatically refreshes your browser with the changes.

If you're like me and need such a minimal feedback loop, it's hard to go wrong with Beefy.

To get started, go ahead and install it:

npm install -g beefy

I've installed it globally because I use it so much. If you'd rather use it on a per-project basis, run:

npm install --save-dev beefy

Either way, using it is straightforward. First, delete your bundle.js. Then, Spin up a new terminal, navigate to your working directory, and run:

beefy main.js --live

Beefy should print some information notifying you that it's listening on

If instead it says, Error: Could not find a suitable bundler!, run this instead:

beefy main.js --browserify $(which browserify) --live

The --browserify $(which browserify) bit tells Beefy to use the global Browserify installation. You don't need this unless you got the error.

We told Beefy to watch main.js. If your entry point has a different name--say, app.js--you'd pass it that instead. The --live switch tells Beefy to automatically rebuild your bundle and reload the browser whenever you change your source code.

Let's see it in action. In your browser, navigate to http://localhost:9966. You should see the same home page we did last time.

Our Initial Web Page

Now, open up main.js, and change squares:

"use strict";

var R = require('ramda');

var square = function square (x) { return x * x; }  
var squares = R.chain(square, [1, 2, 3, 4, 5, 6]); 

document.getElementById('response').innerHTML = squares

Save it, and check out the web page. You should see an updated version of it:

Our Web Page After Update

And if you were watching it as you saved, you'd have noticed it update in real time.

Under the hood, Beefy rebuilds your main.js whenever the server receives a request for bundle.js. Beefy does not save a bundle.js to your working directory; when you need one for production, you'll still have to build that using Browserify. We'll see how to deal with that inconvenience in just a second.

Again, that's all there is to it. If you need anything more specific, the documentation's got your back.

Building a Basic Browserify Configuration

That's it for Browserify: The Essentials. Let's build a small Browserify configuration that:

  • Lets us include either Javascript or Coffeescript dependencies;
  • Displays updates in the client in real time via live reload;
  • Outputs a minified bundle.js with separate sourcemaps when we build manually.

A real, production-quality workflow would do more. But this will show you how to use Browserify to do something nontrivial, and extending it for your own projects should be a cinch.

We'll be using NPM scripts to set this up. In the next section, we'll do it with Gulp.

Let's get to it.

Installing Dependencies

We'll need to install some packages to get this done:

  • Caching-Coffeify, for Coffeescript support while the server is running;
  • Coffeeify, for Coffeescript support when we build our output bundle;
  • Beefy, for live reload;
  • Minifyify, for minfiying our bundle.

You've already got Beefy, so don't worry about installing it. To grab the others, run:

npm install --save-dev caching-coffeeify coffeeify minifyify

Now, let's start building out our scripts. Open up your package.json. You should find a scripts key about halfway down; it should include a key called "tests".

Right after it, add a "serve" task:

"serve" : "beefy main.js --live"

You can see the whole package.json at my GitHub repo. If you had to use the --browserify $(which browserify) option earlier, you'll have to do that here to.

Save that, and back in your terminal, run npm run serve. You should see the same output we got when we ran Beefy earlier.

You may get an ENOSPC error. If you do, run npm dedupe and try again. If that doesn't help, the top answer on this SO thread will solve the problem.

We just associated a command--beefy main.js --live--with a script name--serve. When we run npm run <NAME>, NPM executes the command associated with the name you pass, located in the "scripts" section of your package.json. In this case, np run serve fires up Beefy.

Sweet start. Let's finish it up.

Open up package.json again, and add to your serve script:

"serve" : "beefy main.js --browserify -t caching-coffeeify --live"

When using Beefy, the --browserify option lets you pass options to Browserify. The -t flag tells Browserify you're about to give it a transform to run. Caching-Coffeeify is a transform that compiles Coffeescript to Javascript, and optimizes to make sure it only recompiles what's changed--whenever you want to compile Coffeescript on-the-fly like this, Caching-Coffeeify is a better choice than plain ol' Coffeeify.

Now, we can include Coffeescript files in our project. To see this in action, create list_provider.coffee alongside your main.js:

# list_provider.coffee
"use strict"
module.exports = () => [1, 2, 3, 4, 5]

. . . And in main.js:

// main.js
"use strict";

var R = require('ramda'),
      get_list = require('./list_provider.coffee');

var square = function square (x) { return x * x; }  
var squares = R.chain(square, get_list()); 

document.getElementById('response').innerHTML = squares

Now, run npm run serve, navigate to http://localhost:9966, and everything should still work.

A Build Task

To add a script that build outs a minified bundle with stripped source maps, open up your package.json and add:

/* Remainder omitted */

"serve"         : "beefy main.js --browserify -t caching-coffeeify --live",
"build" : "browserify main.js --debug -t coffeeify -t -p [ minifyify --map bundle.js.map --output build/bundle.map.js ] > build/bundle.js" 

/* Remainder omitted */

Now, in your working directory, run mkdir build. This is the folder we'll save our bundle.js and sourcemap too. Run npm run build; check what's in your build folder; and voilà.

Your Build Folder

Setting Up with Gulp

I assume you're already familiar with Gulp. If not, check out the docs.

Using NPM scripts is fine for simple setups. But it's already clear that this can get cumbersome and unreadable.

That's where Gulp comes in.

In the interest of brevity, we'll just set up a basic task that does the following:

  • Spit out a bundle;
  • Transform Coffeescript via Coffeeify;
  • Transform ES2015 via Babelify;
  • Produce separate source maps.

But if you like bells and whistles, check out the repo. It features a fancy watch task for you to get started with.

As always, the first step is installation:

npm install -g gulp && npm install gulp --save-dev

We'll need to install a bit of a toolchain to make this work. Here's the command; the names of the dependencies are in the Gulpfile below.

npm install --save-dev vinyl-source-stream vinyl-buffer gulp-livereload gulp-uglify gulp-util gulp babelify babel-preset-es2015 buffer merge rename source sourcemaps watchify

Swell. Now, create a Gulpfile that looks like this:

// gulpfile.js
// Heavily inspired by Mike Valstar's solution:
//   http://mikevalstar.com/post/fast-gulp-browserify-babelify-watchify-react-build/
"use strict";

var    babelify   = require('babelify'),
        browserify = require('browserify'),
        buffer     = require('vinyl-buffer'),
        coffeeify  = require('coffeeify'),
        gulp       = require('gulp'),
        gutil      = require('gulp-util'),
        livereload = require('gulp-livereload'),
        merge      = require('merge'),
        rename     = require('gulp-rename'),
        source     = require('vinyl-source-stream'),
        sourceMaps = require('gulp-sourcemaps'),
        watchify   = require('watchify');

var config = {
    js: {
        src: './main.js',       // Entry point
        outputDir: './build/',  // Directory to save bundle to
        mapDir: './maps/',      // Subdirectory to save maps to
        outputFile: 'bundle.js' // Name to use for bundle

// This method makes it easy to use common bundling options in different tasks
function bundle (bundler) {

    // Add options to add to "base" bundler passed as parameter
      .bundle()                                                        // Start bundle
      .pipe(source(config.js.src))                        // Entry point
      .pipe(buffer())                                               // Convert to gulp pipeline
      .pipe(rename(config.js.outputFile))          // Rename output from 'main.js'
                                                                              //   to 'bundle.js'
      .pipe(sourceMaps.init({ loadMaps : true }))  // Strip inline source maps
      .pipe(sourceMaps.write(config.js.mapDir))    // Save source maps to their
                                                                                      //   own directory
      .pipe(gulp.dest(config.js.outputDir))        // Save 'bundle' to build/
      .pipe(livereload());                                       // Reload browser if relevant

gulp.task('bundle', function () {
    var bundler = browserify(config.js.src)  // Pass browserify the entry point
                                .transform(coffeeify)      //  Chain transformations: First, coffeeify . . .
                                .transform(babelify, { presets : [ 'es2015' ] });  // Then, babelify, with ES2015 preset

    bundle(bundler);  // Chain other options -- sourcemaps, rename, etc.

Now if you run gulp bundle in your working directory, you'll have your bundle.js sitting in build/, and your bundle.js.map sitting in build/maps/.

This config is mostly Gulp-specific detail, so I'll let the comments speak for themselves. The important thing to note is that, in our bundle task, we can easily chain transformations. This is a great example of how intuitive and fluent Browserify's API can be. Check the documentationhttps://github.com/substack/node-browserify for everything else you can do with it.


Whew! What a whirlwind tour. So far, you've learned:

  • Why we need Browserify, and why it's awesome;
  • Where Browserify stands in relation to Webpack;
  • How to use Browserify to build a simple bundle;
  • How to use Browserify transforms to build not-so-simple bundles;
  • How to use NPM scripts to set up live reload and build tasks;
  • The basics of integrating Browserify with Gulp

That's more than enough to be productive with Browserify. There are a few links you should bookmark:

And that about wraps it up. If you've got questions, comments, or confusions, drop a line in the comments--I'll get back to you.

Be sure to follow me on Twitter (@PelekeS) if you want a heads-up when I publish something new. Next time, we'll make that boring home page a lot more interesting by using this tooling alongside React.

Until then, keep getting cozy with Browserify. Go build something incredible.

Like this article? Follow @PelekeS on Twitter