Resolves and concatenates CommonJS module dependencies for use in the browser.
Clone or download
Pull request Compare This branch is 3 commits ahead, 4 commits behind tobie:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



Resolves and concatenates CommonJS module dependencies for use in the browser. It's a port of modulr from Ruby to node.js and is based on module-grapher, a node module which resolves dependencies through recursive static analysis.


modulr is available as an NPM module.

$ npm install modulr


modulr accepts the main module's identifier and an optional config object as arguments which get passed to module-grapher. It returns a result object whose output property is a string containing a small runtime and the concatenated modules sources. Optionally, this output can be minified and the module identifiers resolved server-side.

require('modulr').build('foo', {
  paths: ['./lib', './vendor'], // defaults to ['.']
  root: 'path/to/package/root/' // defaults to process.cwd()
  minify: true,                 // defaults to false
  resolveIdentifiers: true,     // defaults to false
  minifyIdentifiers: false,     // defaults to false
  environment: 'prod' // or 'dev', defaults to undefined
}, callback);

// Dump the output to `main.js`.
function callback (err, result) {
  if (err) { throw err; }
  require('fs').writeFileSync('/path/to/main.js', result.output, 'utf8');

modulr can also accepts a CommonJS package or its package.json file as argument. In which case it uses the JSON file's main value as entry point, the package's dir as root, and picks the rest of its options from the JSON file's modulr namespace.

require('modulr').buildFromPackage('path/to/package', callback);

Development Environments

modulr provides a development environment. It is enabled by setting the config option environment to "dev":

require('modulr').build('foo', { environment: 'dev' }, callback);

This does essentially two things.

  1. It sets the global variable __DEV__ to true. This allows adding development-only code (e.g. logging) that is completely stripped out of production builds, e.g.:
if (__DEV__) { console.log('Module Foo loaded.'); }
  1. It adds sourceURL comments to each modules. Rendering engines that support these (at least Gecko and WebKit) will give original file names and line numbers to thrown errors even though all modules are packaged in a single file.


modulr uses Uglify to optionally minify the output. To enable minification, set the minify config option to true. To also minify module identifiers, set the minifyIdentifiers option to true. Note that minification is not compatible with the "dev" environment.

require('modulr').build('foo', { minify: true }, callback);

Lazy evaluation

Lazy evaluation is a technique which allows delaying parsing and evaluation of modules until they are needed (for example, following a user action) while keeping a synchronous programming model.

To lazy eval modules, pass a list of absolute module IDs in the configuration object.

require('modulr').build('foo', {
  lazyEval: ['path/to/module/bar', 'path/to/baz']
}, callback);

or in the package.json file:

  "modulr": {
    "lazyEval": ["path/to/bar", "path/to/baz"]

Resolving identifiers at build time

CommonJS module identifiers can be absolute or relative. Relative identifiers are simplify development but have an extra runtime cost: the path to the module's identifier has to be calculated every time the module is required, and a context aware require function has to be created for every module.

In order to avoid that extra cost, modulr is able to resolve identifiers at build time which produces modified builds which only contain absolute identifiers and uses a lighter runtime. To enable this option, set the resolveIdentifiers config option to true:

require('modulr').build('foo', { resolveIdentifiers: true }, callback);

Instrumenting Performance

As applications become increasingly complex, startup time tends to suffer. While modulr helps mitigate this through optimizations such as resolving identifiers at build time or lazy evaluation, it's sometimes useful to be able to do some serious auditing and find out which modules slow down startup time.

That's what modulr's instrumentPerformance config option enables. Turn it on like so:

require('modulr').build('foo', { instrumentPerformance: true }, callback);

This adds a slew of data to the modulr.perf object available in the global scope (for example, through the console). This data is of the form:

  "start": 1334878573462,            // All times are in ms.
  "defineStart": 1334878573462,      //
  "defineEnd": 1334878573464,        //
  "requireMainStart": 1334878573464, //
  "modules": {                       // Object containing all defined modules.
    "foo": {                         //
      "count": 0                     // Module "foo" has not been required yet.
    },                               //
    "main": {                        // Module "main" has been required once.
      "count": 1,                    // Evaluation of that module and it's
      "left": 1,                     // dependencies took 16 ms.
      "start": 1334878573464,        // Notice the use of nested sets to
      "right": 4,                    // store initialization order.
      "end": 1334878573480           //
    },                               //
    "bar": {                         // Module "bar" has been required twice.
      "count": 2,                    // It was lazy evaluated.
      "left": 2,                     //
      "start": 1334878573466,        //
      "evalStart": 1334878573466,    // Lazy evaluation took 12 ms.
      "evalEnd": 1334878573478,      //
      "right": 3,                    //
      "end": 1334878573480           //
    }                                //
  },                                 //
  "requireMainEnd": 1334878573480,   //
  "end": 1334878573480               //

To visualize this data, just copy and paste it (or in modern browsers, simply drag and drop the JSON file) onto this page. You'll get a beautiful waterfall chart of your application's initialization stage thanks to a little bit of d3.js magic.


Your choice of MIT or Apache, Version 2.0 licenses. modulr is copyright 2010 Tobie Langel.