Google Groups

What is the status of the Asynchronous Module Definition API in Node?


James Fisher May 28, 2011 6:09 AM
Posted in group: nodejs-dev
(With apologies for rant,) I've spent the last couple of days trying to find an elegant way of writing JS that can be run unchanged on the client as well as my server.  This was one of the big incentives for me using Node in the first place: with everyone running JS, this task should be simple.  However, as with many others, I've quickly found out that accomplishing this task is a PITA completely disproportionate to the complexity of the problem.

The sole source of pain is the clash between browser module systems, which are necessarily async, and node module system, which is inherently sync.  There are two possible solutions to this: either complex code transformation/libraries to give one the illusion of sync on the browser, or we simply choose one module style to use on the server and the client.

The first type of solution is exemplified by node-browserify.  This bundles desired code together into one script, thereby allowing the `require` method to be synchronous in the browser.  In order to do this it apparently has to make a massive set of modernizing updates to global objects, weighing in at about 20K compressed, and eliminating the possibility of parallel loading.  Despite working, it feels inelegant.  Despite writing one language everywhere, the developer has to deal with the mysterious complex baggage that makes other solutions (HaXe anyone?) undesirable: boilerplate libraries, difficult debugging, strange line numbers, etc.  *All* solutions of this class are inevitably hacks.  What's more, CommonJS agrees that this is ugly.

The other type of solution, simply choosing one between sync and async modules and using this paradigm consistently, feels so much cleaner.  But which has to give way?  This should be obvious, because implementing a truly synchronous module system in the browser is basically an impossible task.

The sync module system on the server **has** to give way to an async style if we are to ever have an elegant, consistent, and **simple** way of coding for both server and browser.  The costs of the status quo are clear: painful sharing of code, constant switching between paradigms, complexity, and just plain ugliness.  Besides, Node's watchword is "async" -- the fact that the very first line of its Hello World application is a synchronous call appears to be a big inconsistency.

So Node's module system has to change.  There are multiple incompatible async module systems for the browser, but choosing between them isn't that hard: the Asychronous Module Definition spec is backed by CommonJS, has been implemented multiple times (RequireJS being the biggest example), and is already at large in the wild.

What's more, there are already *two* implementations of AMD for node.  The first, RequireJS's r.js script, is a great proof of concept.  However, while just running `node r.js app.js` is easy, this definitely falls in the "temporary monkeypatch" class of solutions: we have to download this script for every app we use, it's another thing to keep up-to-date, it interferes with other dev environments (e.g. CoffeeScript), it feels ugly, and it's the kind of functionality that feels like it really should be in the core.

The other implementation is this pull request opened by Kris Zyp last October, a very small patch that adds native AMD to node.  It was closed without explanation, and the comments asking for justification have not been answered.  If anything comes from me writing this, I'd like an explanation for why this patch was rejected.

TL;DR: Node should support AMD.  This reasons are sound yet I can see no enthusiasm for it from Node developers.  The code even exists already, yet was rejected.  What is holding back native AMD?