Skip to content
NO LONGER MAINTAINED - browserify is too similar and is better (see issues)
JavaScript CoffeeScript
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.

Extensible CommonJS in the browser


Write a main.js as the application entry point

var determine = require('./determine');
console.log(determine.isCool(['clux', 'lava']));

the required module (or .js if you prefer)

cool = require('shared::cool') # cross-domain require
exports.isCool = (input) -> input.filter(cool)

and finally its required cool.js on the shared domain ?

module.exports = function(name){
  return (name === 'clux');

To compile these files invoke modul8() and chain on options

  .domains({'shared': './shared/'})

This will construct a single, browser compatible out.js in your execution path, and the generated dependency tree will look as follows:


The shared code is independent of the application and can be reused on the server.

Compilation can also be performed via the command line interface by typing

$ modul8 client/main.js -p shared:shared/ > out.js

from the path containing fhe shared/ and client/ folders.

To load the CommonJS compatible output file from your site stick a script tag in your HTML:

<script src="/out.js"></script>

Quick Overview

modul8 is an extensible CommonJS code packager and analyzer for JavaScript and CoffeeScript web applications. Applications are recursively analyzed for dependencies from an entry point and will pull in + compile just what is needed.

Code can be shared with the server by isolating modules/libraries in shared domains. This means stand alone logic can exist on the server and be referenced via a normal require(dir+'module'), but also be referenced via require('shared::module') on the client.

To give you full overview and control over what code is pulled in, modul8 automatically generates a depedency tree. This allows fast analysis and identification of extraneous links, and becomes a very important tool for refactoring. Note that the depedency tree is truly a tree because we enforce a strict no circular dependencies rule - allowing these are just bad for modularity.

modul8 supports live extensions of certain exports containers via third party script loaders, and server side data injection at compile time.

Lastly, modul8 aims to eliminate most global variables from your code. It does so using the following approaches

  • Encapsulate all exported data in the closure inhabited by require()
  • Incorporate globally available libraries into the module system via automatic arbiters

To dive in properly; consult the api docs.


  • (extensible) client side require
  • simple code sharing between the server and the client
  • dynamic resolution and compilation of dependencies server-side
  • compiles CommonJS compatible JavaScript, CoffeeScript or hooked in AltJS
  • low footprint: ~1kB (minified/gzipped) output size inflation
  • enforces modularity best practices and logs an npm style dependency tree
  • injecd require data dynamically from the server or live from the client
  • no need to ever maintain include lists or order
  • minimizes global usage, encapsulates exports in closures, absorbs library globals
  • only rebuilds on repeat calls if necessary (files modified || options changed)
  • ideal for single page web applications, 1 or 2 HTTP request to get all code


Install the library:

$ npm install modul8

Install the command line tool:

$ npm install -g modul8

Download the development version:

$ git clone git://


Basic use only only the path to the entry point and an output.


This compiles everything referenced explicitly through app.js to the single browser compatible out.js.

Every require() call is tracked and the resulting dependency tree is loggable. Cross domain require()s are namespaced C++ style: require('shared::validation') will look for a .js then .coffee file named validation on the shared domain. This extra domain must be configured using a chained .domains() call:

  .domains({'shared': './shared/'})

To ensure that the shared domain here can work on the server and the client, any require() calls should be relative and not pull in anything outside that folder. As an example, a same-origin include of shared::defs should be done with a ./ prefix: require('./defs').

The dependency analyzer will typically output something like this if configured

│  └───app::models/user
│  └───app::models/entry
│  └───shared::defs

jQuery can be seemlessly integrated (and will show up in the dependency tree as above) by using .arbiters()

Injecting Data

Data can by injected at compile time from the server by specifying keys and evaluable strings.

  .data({'models': {'user':'clux'}})

The data domain is initialized from the server with every key specified to .data(), but can be extended live on the client. The data API is particularly useful for web applications that needs particular application data to always be bundled. Anything that can be serialized (including pre-serialized string input) can be sent to the data domain.

Using Plugins

Extending the data domain in conjunction with creating specialized domains to handle that data, is a popular method that can be employed by node modules to break browser code down into more managable chunks - while linking them to the server.

This is so useful that it has become the defacto plugin API.

  .use(new Plugin(opts))

This will allow the Plugin to extend 'out.js' with data created in Plugin, as well as add a namespaced require domain on the browser. Using a Plugin will inflate 'out.js' by the size of the data it creates plus only the size of the modules you explicitly require().

Thus, adding plugins is a remarkably safe, monitorable, and robust way, to get discrete units of code - that shares logic with the server - to the client.

Writing your own plugins is also really easy. Please share yours.

Available Plugins

External Injection

Finally, modul8 defines an external domain for asynchronous script loaders to dump their results. This domain can only be used from the client.

Both the data and external domains are only allowed to be modified through safe proxies. Objects residing on these domains can be referenced with require() without messing up the compile time code analysis, but they can still show up in the dependency tree if desirable.

Learn more

The full documentation site should contain everything you could ever want to know about modul8 and probably more. Read it, try it out, and give feedback if you like or hate it / parts of it, or if you want to contribute.

modul8 is my first proper open source project. It was crafted out of necessity, but it has grown into something larger. Version 1.0 should be ready relatively soon - so the current code can be considered mostly stable.

Version 0.10.0 (and probably most before) support node v0.6 - although npm does not seem to work there yet.

Running Tests

Install development dependencies:

$ npm install

Then run expresso

$ expresso

Actively tested with node:

  • 0.4.10


MIT Licensed - See LICENSE file for details

Something went wrong with that request. Please try again.