Browserify for Loading common js modules

Browserify and the Universal Module Definition, We have different module loader & different bundlers to load those modules.

Defining a module is really simple but like all simple things; none of us can agree on just one. While this is generally true for all communities it is especially erratic in the javascript community. This is not really javascript’s fault though. It’s not easy being an extremely flexible, loosely interpreted language available on just about every platform.

The current actively used module definitions are:

Global Variables

// MyDependency is in your global scope
var MyModule = function() {};

CommonJS

var MyDependency = require('my-dependency');
module.exports = function() {};

AMD

define(['my-dependency'], function(MyDependency) {
return function() {};
});

ES6 TO THE RESCUE?

Harmony is on horizon and it includes a module definition:

import { MyDependency } from 'my-dependency';
export function mymodule() {}

Hooray! We’re done… or are we? This may seem like the holy grail but it has a few problems:

BROWSERIFY

Browserify is a great build tool for this. Through transforms it enables you to consume any module.

Install browserify with: npm install browserify -g

CommonJS

Browserify works natively with the CommonJS module definition:

browserify main.js -o bundle.js

which will produce a bundle.js file.

It can be included on your page with:

<script src="bundle.js"></script>
Single Bundle
Using Native Node Modules
Using Watchify
Using Transforms
Creating Vendor Bundles
Minifying Bundles

Writing modules

Now, let’s write a simple module that requires something:

'use strict';
var _ = require('underscore');
var logUnderscoreVersion = function() {
console.log(_.VERSION);
}
module.exports = logUnderscoreVersion;

There are a few things you’ll notice here. First, some of you will immediately point out that I’m using 'use strict' outside of a function, and chastise me because that will apply strict mode to the entire global scope and break all the things! Thankfully, that's not the case here. Browserify encapsulates every module in it's own scope, so strict mode will only apply to the current module.

To use the Underscore library, I’m calling “require” and assigning it to the familiar “_” variable. At the moment, however, this will fail because we haven’t installed it yet. Remedy this with npm:

$ npm install underscore

By calling the “install” command without the “-g” flag, you’re telling npm to install your dependency in the local “node_modules” folder, which it will create for you if needed. Browserify will use that folder to find Underscore and make it available to your module.

Finally, at the end of the module I’m “exporting” the function that I defined. This means that I am making that function available outside of my module. When another module requires my module, the result will be whatever I assigned to “module.exports”. This is how Node.js modules work. Anything I don’t export stays private to my module.

Building a bundle

Now, let’s use the command-line script to build a bundle for the browser. This will include all the required modules in one file. If you saved your module above as “logunderscore.js”, browserify it like this:

$ browserify logunderscore.js > bundle.js

Now you can include bundle.js in an HTML file using a single script tag, and you’re ready to use your JavaScript! Code that is outside of a function will be executed immediately, so a common pattern is to use a “main.js” or an “index.js” as an entry point that requires whatever you need to initialize your app and kicks it off immediately.

Requiring your own modules

When you need to require one of your own modules, use the relative path. You don’t need to add the “.js” at the end of the path.

var logUnderscoreVersion = require('./logunderscore');
logUnderscoreVersion();

Exporting multiple things

If you need to export multiple functions or objects, you can use the “exports” shortcut from Node.js.

'use strict';
var logDate = function() {
console.log(new Date().getDate());
}
var logMonth() {
console.log(new Date().getMonth());
}
exports.logDate = logDate;
exports.logMonth = logMonth;

Then, you can use it like this:

var dateUtils = require('./dateutils');
dateUtils.logDate();
dateUtils.logMonth();

Or like this:

var logDate = require('./dateutils').logDate;
logDate();

Integrating Browserify with build tools

Once you’re comfortable with Browserify, you’ll probably want to integrate it with your favorite build tool.

Browserify and Grunt

In Grunt, you’ll use grunt-browserify. Here’s a config snippet that builds the bundle, and then watches for changes:

'browserify': {
options: {
debug: true,
transform: ['reactify'],
extensions: ['.jsx'],
},
dev: {
options: {
alias: ['react:'] // Make React available externally for dev tools
},
src: ['client/index.js'],
dest: 'build/bundle.js'
},
production: {
options: {
debug: false
},
src: '<%= browserify.dev.src %>',
dest: 'build/bundle.js'
}
},

This config takes advantage of several features, some of which I haven’t mentioned yet. It’s using the reactify transform to precompile JSX files for use with React. It instructs browserify to look for “.jsx” extensions so that you don’t have to include them in your require path. It sets the debug flag so that Browserify will generate source maps for effective debugging in development, but overrides that flag in the production target to keep the build lean.

The “alias” option makes a reqirement available through a global “require” function. This allows you to work with multiple bundles, if you’d like. Here, though, it’s being done so that the React dev tools extension can find React and enable a tab in Chrome. The “alias” setting in the Grunt plugin uses the bundle.require() method from Browserify's API, which is also available with the "-r" flag on the command-line script.

Browserify and Gulp

The gulp-browserify plugin is currently a bit more minimal than its Grunt counterpart, but you can still do everything that you’d like to do by listening for the “prebundle” event and interacting with the bundler API directly.

var browserify = require('gulp-browserify');
var gulp = require('gulp');
var gutil = require('gulp-util');
var rename = require('gulp-rename');

gulp.task('browserify', function() {
var production = gutil.env.type === 'production';
  gulp.src(['index.js'], {read: false})
 //Browserify, and add source maps if this isn't a production build
.pipe(browserify({
debug: !production,
transform: ['reactify'],
extensions: ['.jsx']
}))
    .on('prebundle', function(bundler) {
// Make React available externally for dev tools
bundler.require('react');
})
    // Rename the destination file
.pipe(rename('bundle.js'))
    // Output to the build directory
.pipe(gulp.dest('build/'));
});

you can also explore how are we using webpack as Module loader to load and manage dependancies.

Like what you read? Give Tarun Sharma a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.