Peleke Sengstacke
This tutorial is out of date and no longer maintained.
Browserify changed my life.
… My life as a JavaScript developer, anyway.
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:
Let’s dive in.
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 grab the repo or code along.
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:
<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:
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?
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:
require
syntax, and provides browser-specific shims for much of Node’s core functionality.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 might 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.
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
:
<!doctype html>
<html>
<head>
<title>Getting Cozy with Browserify</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<style>
h1, p, div { text-align: center; }
html { background: #fffffe; }
</style>
</head>
<body>
<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">
</div>
</div>
</div>
<script src="main.js"></script>
<script src="bundle.js"></script>
</body>
</html>
On 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.
squares
;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.
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.
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.
Magic, eh?
Let’s take a look at some additional Browserify fundamentals.
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.
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.
There is 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.
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).
Beefy makes it easy to enable live reload alongside automatic rebuild. It does two big things for you:
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 http://127.0.0.1:9966
.
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.
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:
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.
That’s it for Browserify: The Essentials. Let’s build a small Browserify configuration that:
bundle.js
with separate source maps 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.
We’ll need to install some packages to get this done:
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 too.
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, npm 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
:
"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.
To add a script that builds out 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 source map too. Run npm run build
; check what’s in your build folder; and voilà.
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:
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:
// 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
bundler
.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:
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 confusion, 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.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!