require('modules') in the browser.
Browserify is a development tool that allows us to write node.js-style modules that compile for use in the browser. Just like node, we write our modules in separate files, exporting external methods and properties using the module.exports
and exports
variables. We can even require other modules using the require
function, and if we omit the relative path it'll resolve to the module in the node_modules
directory.
Getting started with the browserify command-line tool requires node.js and npm installed.
npm install browserify -g
multiply.js:
module.exports = function (a, b) {
return a * b;
};
square.js:
var multiply = require("./multiply");
module.exports = function (n) {
return multiply(n, n);
};
index.js:
var square = require("./square");
console.log(square(125)); //=> 15625
Now we have written a couple of modules that require each other, we can run browserify and generate the file for use in the browser:
browserify index.js -o bundle.js
Now that we have a bundle.js
file that bundled the three modules we wrote, we can add a single script tag reference to it into our html page and it'll execute in the browser automatically resolving require
calls. <script src="bundle.js"></script>
and we should see 15625
logged to the JavaScript console.
Since browserify implements the node.js module resolve algorithm, we can easily use npm to install modules from the package manager and use them inside the browser. There are lots of modules on npm that are made for tools such as browserify, but even more exciting is watching modules that were specifically written for node running in a browser environment without any effort. Let's install underscore
and include it in our script.
npm install underscore --save
var _ = require("underscore");
_.each([1, 2, 3], function (n) {
console.log(n); //=> 1, 2, 3
});
The biggest attraction of browserify over similar tools would have to be the inclusion of node.js core modules. Modules such as url
, path
, stream
, events
and http
have all been ported for use in the browser. We can't do everything that node can do, but we can do everything a browser can do using node.js style code.
The most immediately obvious core modules that are useful on the client-side are querystring
, url
and path
. By requiring these core modules, we can easily parse and resolves urls, query strings and paths in a client script. On top of that, the process
, Buffer
, __dirname
, __filename
and global
variables are all populated with Browserify. That means we can use process.nextTick
to easily invoke a function on the next event loop (with full cross-browser support). A special process.browser
flag is also set in browserify builds, so we can do a quick check to see if the script is running in a browser environment (as opposed to node.js for all the cross-environment module developers).
The most powerful feature in Browserify are source transforms. A source transform is a stream injected between the resolved module and the content that is returned. A simple use case for using a source transform is compiling CoffeeScript to JavaScript. Using coffeeify there is no longer a need for precompilation steps, it just works.
There are loads more transforms and you can easily write your own. Some transforms I find myself using regularly are brfs (inlines file contents), hbsfy (precompile Handlebars templates, better performance and smaller footprint), uglifyify (uglify bundled modules with UglifyJS2) and envify (use environment variables within modules).
Using the -d
flag with Browserify will enable source map support. Source maps allow us to view the file in all its natural, multiple file glory. Just make sure you have source maps enabled in your dev tools, and debugging compiled scripts will become 100x easier.
With the -s <name>
option, we can create a bundle for public API consumption with other browser compile and runtime tools. It uses a UMD snippet to define an AMD module, CommonJS module and even falls back to aliasing the name to the window
global.
In a production website environment, you'll probably want to cut down on duplicate code being included by different modules. This can be done by using the -x
flag, which specifies a module that should not be bundled directly with the build and instead required from the page itself. Combine this with the -r
flag to explicitly require modules into a bundle, we can factor out common module dependencies and create a separate bundle.
You'll probably find some module that can't simply be required because it was written for the browser environment. Conviently, we can write a simple polyfill using module.exports = window.$
or similar. But what if it has dependencies in the global that we have used require
with? We could alter the snippet a bit more and alias required modules, but even easier is the browserify-shim module that was written specifically with this purpose in mind.
Lots of people use Grunt everyday to run their build scripts, and browserify is no exception. Grunt-browserify provides an awesome grunt configuration for setting up your browserify builds and even comes with some extra sugar on top, such as a bundled browserify-shim
config option.
Browserify also supports the browser field in package.json
files. This allows module developers to specify specific files that should be used in browser builds, in the case that the module has node-specific code that can't or shouldn't be browserified.
This has been a very brief introduction to Browserify and I haven't even covered everything that is possible. The browserify docs cover plenty of information and additional flags, so definitely take a quick look. Feel free to leave a comment with any issues you have, I'd love to help out and write a follow up post that covers more uses.
Questions? Find me on Twitter or open an issue.