- What is Browserify?
- Why Import node Modules?
- What You’ll Need
- Getting Started
- Creating Your First Browserify File
- Running Browserify for the First Time
- Using the Browserify Output
- Importing Your Own JavaScript Files
- Passing in Variables and Sharing Modules Across Our App
- Managing Browserify’s npm Dependencies with package.json
- Automating the Browserify Process
- Conclusion
- Other Resources
- Frequently Asked Questions (FAQs) about Getting Started with Browserify
JavaScript implementations have been getting more and more complex as the beautiful beast we call the web evolves each year. Many of us now work with JavaScript modules – independently functioning components that come together to work as a cohesive whole, yet can happily have any component replaced without causing armageddon. Many of us have been using the AMD module pattern and RequireJS to accomplish this neatly.
Last year, Browserify hit the scene and brought on a lot of excitement. As the dust starts to settle, I wanted to write up an overview on what Browserify is, how it works, and a few options for adding it into your workflow.
What is Browserify?
Browserify allows us to use node.js style modules in the browser. We define dependencies and then Browserify bundles it all up into a single neat and tidy JavaScript file. You include your required JavaScript files using require('./yourfancyJSfile.js')
statements and can also import publicly available modules from npm. It’s also quite simple for Browserify to generate source maps for you so that you can debug each JS file individually, despite the fact it’s all joined into one.
Why Import node Modules?
Importing modules is a blessing – rather than visit a range of sites to download libraries for your JavaScript, just include them using require()
statements, ensure that the modules have been installed and you’re good to go. Commonly used JavaScript libraries like jQuery, Underscore, Backbone and even Angular (as an unofficial distribution) are all available to work with. If you’re working on a site that already runs node, you’re simplifying things even further with one common way to structure all of your JS. I really like that concept.
What You’ll Need
To get started with Browserify, the bare minimum you’ll need is:
- node.js
- npm – this comes installed with node by default.
- Browserify – I’ll explain how to install this one.
- A pack of JavaScript modules you’re ready to tame!
Getting Started
To get started, you’ll need node and npm installed on your computer. Head to the links above if you’re looking for guidance on getting these installed. If you’re totally stuck, try these instructions on installing Node.js via package manager. You won’t need to actually do any node work to use Browserify. We’re installing node solely because npm runs off it. Once you’ve got npm, you can install Browserify using the following command:
npm install -g browserify
What we’re doing here is using npm to install Browserify globally on your machine (the -g
tells npm to install a module globally).
If you get an error that starts with the following:
Error: EACCES, mkdir '/usr/local/lib/node_modules/browserify'
Then you have a permission issue. You can sudo
the command, but I recommend checking out this post instead.
Creating Your First Browserify File
Let’s start by creating a Browserified JavaScript file that imports an extremely popular module, Underscore. We’ll use Underscore to track down Superman. I’ve called my JS file main.js
, and have placed it in a js
folder in my project.
We start by assigning the _
variable to Underscore using Browserify’s require()
statement in our JavaScript:
var _ = require('underscore');
Next, we’ll use the each()
and find()
functions from Underscore. We’ll search through two arrays of names and run a console.log
to say whether it sees Superman or not. Highly advanced stuff Lex Luthor could only dream of. Our final JavaScript code will look like this:
var _ = require('underscore'),
names = ['Bruce Wayne', 'Wally West', 'John Jones', 'Kyle Rayner', 'Arthur Curry', 'Clark Kent'],
otherNames = ['Barry Allen', 'Hal Jordan', 'Kara Kent', 'Diana Prince', 'Ray Palmer', 'Oliver Queen'];
_.each([names, otherNames], function(nameGroup) {
findSuperman(nameGroup);
});
function findSuperman(values) {
_.find(values, function(name) {
if (name === 'Clark Kent') {
console.log('It\'s Superman!');
} else {
console.log('... No superman!');
}
});
}
We’ll want to ensure that Browserify can find the npm module when it tries to add it to our project. The bare basics of doing so involves opening up your terminal, navigating to the folder which holds your JavaScript project, and then running this command to install Underscore in that folder:
npm install underscore
For those unfamiliar with how node and npm work, this creates a folder called node_modules
in your project which holds the code for your Underscore module. The command retrieves the latest version of Underscore from the npm repository at https://registry.npmjs.org/underscore
. With that module in our node_modules
folder, Browserify can now find it and use it.
Running Browserify for the First Time
When we run Browserify, it’ll want to build a new JavaScript file with all of our attached modules. In this case, it’ll build a JavaScript file with Underscore inside it. We’ll need to decide on a name for this new file, I’ve gone with findem.js
. I run this command from my project’s root folder:
browserify js/main.js -o js/findem.js -d
This command reads your main.js
file and outputs it into the findem.js
file defined by the -o
option. I’ve included the -d
option so that it’ll generate a source map for us too, this way we can debug main.js
and underscore
cleanly as separate files.
Using the Browserify Output
From there, it’s as simple as including the file on your page like any other JS file:
<script src="js/findem.js"></script>
Importing Your Own JavaScript Files
It’s unlikely that all of your application will come from node modules. To include your own JavaScript, you can use the same require()
function. The following line of JavaScript will import a JS file called your_module.js
into the greatestModuleEver
variable:
greatestModuleEver = require('./your_module.js');
To import our JavaScript like this, we just need to structure our JavaScript as a module. To do so, we must define module.exports
. One way to do this is shown below.
module.exports = function(vars) {
// Your code
}
Side Note!
If you’ve got a bunch of JavaScript libraries that aren’t in npm and you’re looking for an easier way to get these all into Browserify, you can use the Browserify-shim npm module to convert these files for you. We won’t be using it in this article but some devs might be keen to give that a go.
Our Example with a Module
To give a simple example of how this works, we’ll take out the arrays from the previous superhero search example and replace them with a separate JS module that returns an array of names. The module looks like so:
module.exports = function() {
return ['Barry Allen', 'Hal Jordan', 'Kara Kent', 'Diana Prince', 'Ray Palmer', 'Oliver Queen', 'Bruce Wayne', 'Wally West', 'John Jones', 'Kyle Rayner', 'Arthur Curry', 'Clark Kent'];
}
Next, we’ll import that module into our code using names = require('./names.js')
:
var _ = require('underscore'),
names = require('./names.js');
findSuperman(names());
function findSuperman(values) {
_.find(values, function(name) {
if (name === 'Clark Kent') {
console.log('It\'s Superman!');
} else {
console.log('... No superman!');
}
});
}
Our names
variable references the exported function from our module. So we use the names
variable above as a function with brackets when we pass in the array of names to our findSuperman()
function.
Run that browserify
command from your command line once again to compile it, open it in your browser, and it should run as expected, searching through each value in the array and logging whether it sees Superman or not:
Passing in Variables and Sharing Modules Across Our App
To add a bit more complexity to this rather simple Superman hunting app, let’s turn our findSuperman()
function into a module. That way, we could theoretically find Superman in various parts of our JavaScript and we could always replace our Superman hunting module with a more effective one in future quite easily.
We can pass in variables to our module and use them in our module.exports
function, so we’ll create a module in a file called findsuperman.js
which expects to be given an array of names:
module.exports = function (values) {
var foundSuperman = false;
_.find(values, function(name) {
if (name === 'Clark Kent') {
console.log('It\'s Superman!');
foundSuperman = true;
} else {
console.log('... No superman!');
}
});
return foundSuperman;
}
I’ve added a return value for our findSuperman()
function. If it finds Superman, it’ll return true. Otherwise, it’ll return false. It’s up to the code that uses this module to decide what it uses this true/false value for. However, there’s one thing we’re missing in the module above. We’re using Underscore in our function, but haven’t declared it. We can declare it in the module itself as well at the top like so:
var _ = require('underscore');
module.exports = function (values) {
...
When using Browserify, it’ll look through all of your JS files that are imported and will only import each module that is mentioned once. So we’re requiring underscore in our main JS file and we’re requiring it in findsuperman.js
but when Browserify packages it all up, it only puts it in our final JS file once. Pretty neat right?
Our actual JavaScript app will now use our new module with its new returned true/false value. For demo purposes, we’ll just stick to a simple document.write
to say whether or not it found Superman from our names:
var _ = require('underscore'),
names = require('./names.js'),
findSuperman = require('./findsuperman.js');
if (findSuperman(names())) {
document.write('We found Superman');
} else {
document.write('No Superman...');
}
We don’t even need to import Underscore in our main JS file anymore, so you could remove it without any drama. It’ll still get imported in the end through its inclusion in the findsuperman.js
file.
Managing Browserify’s npm Dependencies with package.json
Say you have a keen friend who’d like to also use your code. It’d be a bit tough to expect them to know they need to install the npm underscore module first. The solution to this is creating a file called package.json
in the root of your project. This file gives your project a name (make sure there are no spaces in the name here), description, author, version and most importantly in our case – a list of npm dependencies. For those who’ve developed with node, we’re using the exact same stuff here:
{
"name": "FindSuperman",
"version": "0.0.1",
"author": "Patrick Catanzariti",
"description": "Code designed to find the elusive red blue blur",
"dependencies": {
"underscore": "1.6.x"
},
"devDependencies": {
"browserify": "latest"
}
}
The list of dependencies is currently limited to our single "underscore": "1.6.x"
, where the first part of the dependency is the name and the second part is the version. latest
or *
will retrieve the latest version npm has. Alternatively, you can put in numbers such as 1.6
(for version 1.6) and 1.6.x
(for versions 1.6.0 up to but not including 1.7).
We can also include browserify itself as a dependency, however it isn’t a dependency for the project to run – any user to our app can find Superman without needing to run Browserify. It is one of our devDependencies
– modules required for developers to make updates to this app.
Now we’ve got a package.json
file, we don’t need to get our friend to run npm install underscore
. They can just run npm install
and all necessary dependencies will be installed into their node_modules
folder.
Automating the Browserify Process
Running browserify
in the command line every single time you change the file is annoying and not at all convenient. Luckily there are a few options available to automate the running of Browserify.
npm
npm itself is able to run command line scripts just like the ones you’ve been typing in manually. To do so, just place a scripts
section into your package.json
like so:
"scripts": {
"build-js": "browserify js/main.js > js/findem.js"
}
To run that, you can type the following in your command line:
npm run build-js
But that’s not convenient enough. We’ve still got to run that command manually each time. That’s annoying. So a better option is to use an npm module called watchify. Watchify is simple, it’s easy and it’s a huge time saver. It’ll watch for changes to your JS and automagically re-run Browserify.
To get this into our package.json
, we’ll add it to our devDependencies
and include a new script for watching our JS (leave build-js
there for times when we do want to build our JS without needing to change the file).
"devDependencies": {
"browserify": "latest",
"watchify": "latest"
},
"scripts": {
"build-js": "browserify js/main.js > js/findem.js",
"watch-js": "watchify js/main.js -o js/findem.js"
}
To run this, just type in the following command.
npm run watch-js
It will run and work its magic. It doesn’t say much though to let you know what’s going on, which can be confusing. If you’d prefer it to give you details on what it’s doing, add -v
to your watchify command like so:
"watch-js": "watchify js/main.js -o js/findem.js -v"
That’ll give you feedback like this each time it runs:
121104 bytes written to js/findem.js (0.26 seconds)
121119 bytes written to js/findem.js (0.03 seconds)
Generating Source Maps in npm
To generate source maps using npm, add -d
after your browserify
or watchify
command:
"scripts": {
"build-js": "browserify js/main.js > js/findem.js -d",
"watch-js": "watchify js/main.js -o js/findem.js -d"
}
To have both the -d
for debugging and -v
for verbose output in watchify
you can combine them like so:
"watch-js": "watchify js/main.js -o js/findem.js -dv"
Grunt
A lot of people (myself included) have been using Grunt for a while now and are pretty used to it. Luckily, for those sorts, Browserify plays nicely with Grunt builds too!
We’ll need to change our package.json
file in order to use grunt. We won’t be using the scripts
section anymore, and instead will be relying on Grunt for that. Instead we’ll add a few new devDependencies
:
{
"name": "FindSuperman",
"version": "0.0.1",
"author": "Patrick Catanzariti",
"description": "Code designed to find the elusive red blue blur",
"dependencies": {
"underscore": "1.6.x"
},
"devDependencies": {
"browserify": "latest",
"grunt": "~0.4.0",
"grunt-browserify": "latest",
"grunt-contrib-watch": "latest"
}
}
We’ve added to our dependencies:
- grunt – to ensure we’ve got Grunt installed for the project.
- grunt-browserify – the module that’ll allow you to run Browserify inside Grunt.
- grunt-contrib-watch – the module that’ll watch our files and run Browserify any time they change.
We then create a file called gruntFile.js
in the root of our project. Inside this Grunt file we’ll have the following:
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-browserify');
grunt.registerTask('default', ['browserify', 'watch']);
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
browserify: {
main: {
src: 'js/main.js',
dest: 'js/findem.js'
}
},
watch: {
files: 'js/*',
tasks: ['default']
}
});
}
We start in our Grunt file by loading the npm modules that we required in our package.json
file:
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-browserify');
We register our one and only group of tasks we’d like to run as our default
task (browserify
and watch
):
grunt.registerTask('default', ['browserify', 'watch']);
We set up our Grunt initConfig
object (all Grunt files look for this):
grunt.initConfig({
Within that, we point out where our package.json
file is:
pkg: grunt.file.readJSON('package.json'),
Our Browserify settings are next and they basically set up where our source JS file is with our Browserified code and the file we’d like that to be built to:
browserify: {
main: {
src: 'js/main.js',
dest: 'js/findem.js'
}
},
We then set up a watch
task to rerun our Browserify task whenever anything changes in the js
folder:
watch: {
files: 'js/*',
tasks: ['default']
}
Because of our new devDependencies
(we don’t have Grunt installed in our project, nor do we have either of those modules), we’ll need to npm install
first. Once you’ve allowed it to run and install any modules, you can then run the ever so simple grunt
command to get it to start watching your project.
Generating Source Maps in Grunt
With version 2.0.1 of grunt-browserify
, the way that source maps need to be defined changed causing a lot of guides online to be incorrect! The correct way to get Grunt and Browserify to generate source maps for you is to add debug: true
inside bundleOptions
within options
like so:
browserify: {
main: {
options: {
bundleOptions: {
debug: true
}
},
src: 'js/main.js',
dest: 'js/findem.js'
}
},
That complicated looking options set up is intended to allow for the inclusion of future Browserify options in a nice and easily compatible way.
Gulp
Gulp is Browserify’s tabloid lover. Articles around the web pair the two quite often, Browserify and Gulp – the cutting edge JavaScript build process made in heaven. I wouldn’t say Browserify fans need to use Gulp, it’s mostly a personal preference between the different syntaxes. You can (as you’ve seen above) quite happily use npm or Grunt to build your Browserify file. I’m personally a fan of the clean and simple npm build process for smaller projects.
To do the above in Gulp, we’ll start by installing Gulp globally:
npm install -g gulp
We’ll update our package.json
file to include a few new devDependencies
we’ll need:
"devDependencies": {
"browserify": "latest",
"watchify": "latest",
"gulp": "3.7.0",
"vinyl-source-stream": "latest"
}
We’ve added the following:
- watchify – we used this above in the npm example too. Same module.
- gulp – the rather important module to give us all that Gulp goodness!
- vinyl-source-stream – this is the module that’ll take an input and return a file for us to put somewhere.
Browserify has a streaming API for its output that we can use directly in Gulp. A bunch of guides will suggest using the gulp-browserify
plugin, however Browserify do not recommend this and prefer us using Browserify’s streaming API output. We use vinyl-source-stream
to pick up this Browserify output and place it into a file for us to output somewhere.
We then create a file called gulpfile.js
in the root of our project. This is where all the Gulp functionality will go:
var browserify = require('browserify'),
watchify = require('watchify'),
gulp = require('gulp'),
source = require('vinyl-source-stream'),
sourceFile = './js/main.js',
destFolder = './js/',
destFile = 'findem.js';
gulp.task('browserify', function() {
return browserify(sourceFile)
.bundle()
.pipe(source(destFile))
.pipe(gulp.dest(destFolder));
});
gulp.task('watch', function() {
var bundler = watchify(sourceFile);
bundler.on('update', rebundle);
function rebundle() {
return bundler.bundle()
.pipe(source(destFile))
.pipe(gulp.dest(destFolder));
}
return rebundle();
});
gulp.task('default', ['browserify', 'watch']);
We start by importing in our npm modules which is fairly self explanatory. We then set three variables for our build:
sourceFile
– the location and filename of our Browserified file (in this casejs/main.js
)destFolder
– the folder location we are outputting the final file todestFile
– the filename we want our final file to have
I’ll explain the code in a bit more detail below.
How Browserify and Gulp work together
Our first task is our browserify
one which we define like so:
gulp.task('browserify', function() {
It first passes our main.js
file into the Browserify npm module:
return browserify(sourceFile)
We then use the Browserify streaming API to return a readable stream with our JavaScript content:
.bundle()
From there, we pipe it into a file with the filename findem.js
and then pipe that through to Gulp to put into our js
folder.
.pipe(source(destFile))
.pipe(gulp.dest(destFolder));
We’re basically taking our input through various stages that eventuates into our final project which should be a shiny new JavaScript file!
Combining Watchify and Gulp
As learnt previously, it’s a little annoying to use Browserify directly as it’s much easier to have it run automatically when you update the file. To do this, we use the watchify
npm module again.
We start by setting up a task called watch
(you could call it watchify
if you’d like… it’s really up to you here):
gulp.task('watch', function() {
We assign the watchify module to the bundler
variable as we’ll use it twice:
var bundler = watchify(sourceFile);
We then add an event handler which runs a function called rebundle()
anytime the update
event is called. Basically, whenever watchify sees the file change, it’ll run rebundle()
:
bundler.on('update', rebundle);
So what is rebundle()
? It’s pretty much exactly what our browserify
task was doing above:
function rebundle() {
return bundler.bundle()
.pipe(source(destFile))
.pipe(gulp.dest(destFolder));
}
return rebundle();
});
It’d be possible to merge both browserify
and watchify
together in some keen JavaScript optimisation but I decided to leave them separately in this article to keep things simple. For an impressive and more complex example of this, check out Dan Tello’s starter Gulp file.
To finish our gulpfile.js
, we define our default task which works the same way as the default task in grunt.
gulp.task('default', ['browserify', 'watch']);
To run the above Gulp code, you’ve got three options. The easiest way is to run that default task you made, which requires only one word on the command line:
gulp
That’ll run the browserify
task once and the watch
task will begin watching the files for any changes.
You can also specifically run your browserify
task:
gulp browserify
Or your watch
task:
gulp watch
Generating Source Maps Using Gulp and Browserify
To generate a source map for your JavaScript, include {debug:true}
in both bundle()
functions.
Our browserify
task would look like so:
gulp.task('browserify', function() {
return browserify(sourceFile)
.bundle({debug:true})
.pipe(source(destFile))
.pipe(gulp.dest(destFolder));
});
The rebundle()
function in our watch
task would look like so:
function rebundle() {
return bundler.bundle({debug:true})
.pipe(source(destFile))
.pipe(gulp.dest(destFolder));
}
Conclusion
It’s still quite early days for Browserify and it will surely evolve and mature as time progresses. In its current state, it is already a very handy tool for structuring your modular JavaScript and is especially brilliant for those who are using Node on their backend. Code becomes much cleaner for Node developers when using npm modules in both the front and back end of a project. If you haven’t given Browserify a shot, try it in your next JavaScript project and see if it rocks your world.
Other Resources
There are a ton of other Browserify resources out there. A few handy bits and pieces you might want to check out:
- The Browserify Handbook – James Halliday’s ever so valuable handbook on getting started with Browserify. Definitely worth a read!
- Gulp + Browserify: The Everything Post by Dan Tello – Really thorough article showing more advanced usages.
- And just like that Grunt and RequireJS are out, it’s all about Gulp and Browserify now – Martin Genev talks about his sudden conversion to Browserify and Gulp with an example.
- An Introduction to Gulp.js – More info on how to use Gulp by Craig Buckler.
Frequently Asked Questions (FAQs) about Getting Started with Browserify
What is the main purpose of Browserify?
Browserify is a development tool that allows developers to write Node.js-style modules that compile for use in the browser. With Browserify, you can require(‘modules’) in the browser by bundling up all of your dependencies. This tool is particularly useful because it lets you use most of the npm packages directly in the browser, which can significantly speed up the development process.
How does Browserify differ from other module bundlers?
Unlike other module bundlers, Browserify was specifically designed to allow developers to write Node.js-style modules for the browser. It does this by recursively analyzing all the require() calls in your app in order to build a bundle you can serve up to the browser in a single script tag. Browserify also has a rich plugin ecosystem, which allows you to customize your build to a great extent.
How can I install Browserify?
You can install Browserify globally on your system using npm (Node Package Manager). The command for this is ‘npm install -g browserify’. Once installed, you can use it from the command line to bundle your JavaScript files.
How do I use Browserify in my project?
To use Browserify, you first need to write your code using the CommonJS module format. Then, you can use Browserify from the command line to bundle your main JavaScript file along with all its dependencies into a single file. This bundled file can then be included in your HTML file using a script tag.
Can I use ES6 modules with Browserify?
Yes, you can use ES6 modules with Browserify, but you’ll need to use a transpiler like Babel to convert your ES6 code into ES5 code that Browserify can understand. You can do this by installing Babel and the Babelify transform, and then using them in your Browserify command.
How can I use npm packages in the browser with Browserify?
With Browserify, you can use most npm packages directly in the browser. To do this, you first need to install the package using npm. Then, you can require the package in your JavaScript file, and Browserify will ensure that it’s included in your bundle.
What are transforms in Browserify?
Transforms are plugins that Browserify uses to compile or transform your code. For example, you can use the Babelify transform to compile your ES6 code into ES5 code. Transforms can be applied globally or to specific files, and you can use multiple transforms in your project.
How can I debug my bundled code?
Browserify has a built-in option for generating source maps, which can help you debug your bundled code. To generate a source map, you can use the ‘–debug’ option in your Browserify command. This will include source mapping data in your bundle, which can then be used by the browser’s developer tools to help you debug your code.
Can I use Browserify with a task runner like Gulp or Grunt?
Yes, you can use Browserify with task runners like Gulp or Grunt. Both Gulp and Grunt have plugins available that can be used to integrate Browserify into your build process. This can help automate the process of bundling your JavaScript files.
How can I optimize my bundle for production?
There are several ways to optimize your Browserify bundle for production. One common method is to minify your bundle using a tool like UglifyJS. You can also use the ‘tinyify’ plugin, which is a Browserify plugin that applies various optimizations to your bundle to make it as small as possible.
![Patrick Catanzariti](https://uploads.sitepoint.com/wp-content/uploads/2016/08/1472550792patrick-catanzariti-dev-diner-profile-125x125-96x96.jpg)
PatCat is the founder of Dev Diner, a site that explores developing for emerging tech such as virtual and augmented reality, the Internet of Things, artificial intelligence and wearables. He is a SitePoint contributing editor for emerging tech, an instructor at SitePoint Premium and O'Reilly, a Meta Pioneer and freelance developer who loves every opportunity to tinker with something new in a tech demo.