I haven't documented yet but there is something I'm working on for a while, OneJS. It generates a single, stand-alone JavaScript file, not requiring coder to make any change on a CommonJS code. The built file it generates can be run at any platform that doesn't support CommonJS, such as web browsers. It means that we can use the great dependency mechanism NPM provides in our frontend apps.
For those who wonders, OneJS; https://github.com/azer/onejs
Example project; https://github.com/azer/onejs/tree/master/test/example-proje...
Output of the above example project; https://gist.github.com/1286969
A relatively larger example; https://github.com/azer/multiplayerchess.com/tree/master/fro...
Is there something that differentiates your approach? I do actually think there's room for improvement in these libraries, so I'm genuinely curious.
I put all my client-side JS files into ./src directory and watch them with Node.js server. When any file in ./src is added or modified then server automatically copies it to ./build directory and wraps it with additional code required by module loader.
This way I can use (almost) the same syntax for handling modules on both client- and server-side, e.g. I can write client-side script which looks like this:
var button = require('widgets/button.js').button;
var toggleButton = Object.extend(button, {
label: 'Toggle me',
});
exports.toggleButton = toggleButton;
And it will automatically get compiled into: 'use strict'; module('widgets/toggleButton.js', function(exports) {
var button = require('widgets/button.js').button;
var toggleButton = Object.extend(button, {
label: 'Toggle me',
});
exports.toggleButton = toggleButton;
});
The client-side framework for handling such modules takes 28 lines of code: https://gist.github.com/1287050Unless you are writing really large apps, this approach seems to be much cleaner, just remember to combine and minify all modules before deployment.
For instance, your approach doesn't support assigning to `module.exports` (just a few more lines of code), relative paths (a few dozen more lines), or the path resolution used by `require.resolve` (a few dozen more).
For small apps it's probably fine, and I've used something very similar. But it's not always easy to decide "this will be a small app" up front. And then there's the issue that even if your app is small, `require` will be doing something very different in Node (complex path resolution) than in the browser, and it could lead to confusing results or a lying test suite.
We ended up using Browserify instead. It's a Node.js module that lets you use CommonJS-style require in your client-side code. Browserify scans your code for all requires, figures out in which order the dependencies should be loaded and merges the code. Optionally, it lets you compile CoffeeScript on the fly or use filters, such as UglifyJS (to minify the output). Another great advantage, IMO, is that Browserify can package most Node.js modules for client-side use. Instead of downloading & distributing JS libs, you can manage them as modules via NPM and require them as you would in Node.js apps. Browserify will grab the code from the module and package it for you.
However, if you can't use Node.js on your server, Require.js is definitely the way to go.
Browserify is great with Node. For a slightly different take on how to share code with the server, you might also want to check out https://github.com/clux/modul8 : )
I think it's a great combination! And after finishing three commercial projects with it we have yet to run into any brick walls... Unlike with many other JS MVC frameworks, which in my opinion, try to do too much for you.