modulr
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.
Install
modulr
is available as an NPM module.
$ npm install modulr
Usage
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'],
root: 'path/to/package/root/'
minify: true,
resolveIdentifiers: true,
minifyIdentifiers: false,
environment: 'prod'
}, callback);
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.
- 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.'); }
- 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.
Minification
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,
"defineStart": 1334878573462,
"defineEnd": 1334878573464,
"requireMainStart": 1334878573464,
"modules": {
"foo": {
"count": 0
},
"main": {
"count": 1,
"left": 1,
"start": 1334878573464,
"right": 4,
"end": 1334878573480
},
"bar": {
"count": 2,
"left": 2,
"start": 1334878573466,
"evalStart": 1334878573466,
"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.
License
Your choice of MIT or Apache, Version 2.0 licenses. modulr
is copyright 2010 Tobie Langel.