Browser-Side Node.js Style Modules require() and exports with Browserify

Browserify is an excellent tool that lets you use CommonJS modules right in the browser by bundling them up into a single large file. If you are well acquainted with Node and it’s way of loading modules via require('module') and exporting them using module.exports = ..., this is the exact pattern browserify brings to the browser. Not only can you write your own modules in this format and load/export them, but you can also use those installed via npm!

Installation

Installing it (globally) is as easy as installing any other module via npm –

What's the one thing every developer wants? More screens! Enhance your coding experience with an external monitor to increase screen real estate.

$ npm install -g browserify

Usage

Let’s setup some quick files to dive into the usage. First creating an index.html with the following code –

<!doctype html>
<title>Testing Browserify</title>
<h1>My Heading</h1>
<script src="bundle.js"></script>

Next up we code our main.js file with some require() calls to load our dependencies.

var dom = require('./dom');
var outliner = require('./libs/outliner');

dom.get('body').style.backgroundColor = 'whiteSmoke';
outliner.heading(dom.get('h1'));

We pass relative paths to the require() calls just like we do in Node, so its going to search the current working directory for the files. Let’s create them with some sample code too!

// dom.js

var get = function (selector) {
	return document.querySelector(selector);
};

exports.getAll = function (selector) {
	return document.querySelectorAll(selector);
};

exports.get = get;

The next one is inside a folder called libs, this is just to demonstrate that your dependency scripts can lie inside folders too, not just the working directory of main.js.

// ./libs/outliner.js

var outlineHeading = function (heading) {
	heading.style.border = '1px solid black';
};

module.exports = {
	heading: outlineHeading
};

.. and we’re done! All we need to do now is build a bundle out of main.js. We’ll name it bundle.js which is what we load inside index.html. In order to do so –

$ browserify main.js # dump bundled code to stdout
$ browserify main.js > bundle.js # dump into a file

During the process, browserify looks up all the modules required by main.js and includes them in the bundled source. Loading Node.js core modules or vendor packages installed via npm is also possible! It’ll search node_modules at every level in the filesystem tree hierarchy just like Node does until it finds the module.

var util = require('util'); // built-in
console.log( util.format('%s:%s', 'foo', 'bar', 'baz') ); // 'foo:bar baz'

var hat = require('hat'); // vendor, https://github.com/substack/node-hat
console.log(hat()); // dumps a random string like 'be72a02e2962ee2d18dd4a1d1399691b'

Try $ browserify --help to check out the different options (and their purpose) available.

External Requires

We can create bundles of several modules and export a require() function (global namespace) to load those modules in other scripts. For example –

$ browserify -r util -r hat -r ./dom > bundle.js

Then in a script tag or file –

<script src="bundle.js"></script>
<script>
	var util = require('util');
	var hat = require('hat');
	var dom = require('./dom');
	
	// more code ...
</script>

Note – If browserify finds another require() function already defined in the global scope beforehand then it’ll safely fallback to that if the module you specified is not found.

Say you have 2 webpages that loads substantial amount of different JS code yet has a lot of shared modules too. We can throw all the shared modules in one bundle and other parts of code in another one, excluding shared code from the page-specific bundle that would otherwise get included due to require('module_name') call. To illustrate this, let’s modify our first example to incorporate jQuery 1.9.1. So save jQuery in jquery.js and then since it doesn’t exports itself as a commonjs module, we’ll have to do so manually in a separate file. Something like this works well –

// jquery_module.js

// jQuery does not export as commonjs module (until 2.x)
require('./jquery');

// The code is loaded now, so we can export ourself
module.exports = window.jQuery;

We’ve learnt how to work with libraries that just define globals.

We’ll just modify our libraries to use the new jquery module. Also we assume that page-1.html uses dom.js.

// dom.js

var $ = require('./jquery_module');

var get = function (selector) {
	return $(selector).eq(0);
};

exports.getAll = function (selector) {
	return $(selector);
};

exports.get = get;

page-2.html uses ./libs/outliner.js that gets changed to –

// ./libs/outliner.js

var $ = require('../jquery_module');

var outlineHeading = function () {
	$('h1').css('border', '1px solid black');
};

module.exports = {
	heading: outlineHeading
};

So basically what we’ve done is wrap jQuery into jquery_module.js to export it manually and made our custom libraries depend upon it. Now first we bundle our common/shared code.

$ browserify -r ./jquery_module > common.js

Next we create our bundles to use on different pages without them containing the contents from jquery_module.js or jquery.js.

$ browserify -x ./jquery_module.js -x ./jquery.js dom.js > dom_bundle.js
$ browserify -x ./jquery_module.js -x ./jquery.js ./libs/outliner.js > ./libs/outliner_bundle.js

Now first page can have –

<script src="common.js"></script>
<script src="dom_bundle.js"></script>

while the second one can have –

<script src="common.js"></script>
<script src="libs/outliner_bundle.js"></script>

Hope that makes sense! The code contained in dom and outliner script files aren’t very concrete real life examples but hopefully you get the ideas.

Source Maps

Browserify will inline base64-encoded source maps if you build with the --debug option.

$ browserify --debug main.js > bundle.js

Source Transforms

There are some modules that can be used along with browserify -t to do various types of source transformations. For example coffeeify allows compiling coffeescript code to javascript. Sample usage (assuming your coffee code is in main.coffee) –

$ npm install coffeeify
$ browserify -t coffeeify main.coffee > bundle.js

Here’s a list of all the currently known modules to achieve various types of transforms.

The API

Browserify ships with an API that you can use to generate bundles programmatically. Here’s a basic example of how to use the API –

// browserify.js
// execute like this - $ node browserify.js

var browserify = require('browserify');

var bundle = browserify();
// Add files to the bundle
bundle.add('./foo.js');
bundle.add('./bar.js');

// Bundle everything
bundle.bundle({}, function (err, src) {
	// Serve `src` as direct response or store in a file
	console.log(src);
});

Conclusion

Overall the tool is pretty nice. It always bundles your code, you can use Node.js core modules, install any vendor module via npm and use them, source maps for better readability and debugging of code, neat API, our beloved module.exports = ... syntax and much more.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download

Author: Rishabh

Rishabh is a full stack web and mobile developer from India. Follow me on Twitter.

2 thoughts on “Browser-Side Node.js Style Modules require() and exports with Browserify”

  1. Dear Rishabh,

    there is a code block in article which you generated bundles with browserify. The line that I mentioned is :

    $ browserify -x ./jquery_module.js -x ./jquery.js ./libs/outliner.js > ./libs/outliner_bundle.js

    I am not sure whether right or not but you written in next line :
    <script src="libs/outliner.js"></script>

    whereas it should be <script src="libs/outliner_bundle.js"></script>

    The reason is to think this way greater than ( > ) symbol. Normally, right side of the operator is output.

Leave a Reply

Your email address will not be published. Required fields are marked *