CommonJS: the First Year

Jan 29, 2010 14:53 · 1740 words · 9 minute read CommonJS

A year ago today, I posted “What Server Side JavaScript Needs”, inviting people to come and turn JavaScript into a competitive platform for applications on the server. Quite a few people answered the call. While the focus of the group has been on JavaScript in non-browser contexts, we’re ultimately shooting for as much of a standard that can cross between server, browser, GUI and command line applications as possible. That’s why we changed the name to CommonJS in the second half of the year. Ironically, most of my own personal use of CommonJS so far has been in the browser. I’ll come back to the personal perspective, though.

The Original Goals

As laid out in my original blog post, we were seeking to create:

  • A module system,
  • A cross-interpreter standard library,
  • A few standard interfaces,
  • A package system, and
  • A package repository

Note that the idea here is that this group creates specs, which will have multiple implementations.

The goal is to have these things working across as many operating systems and interpreters as possible. There are three major operating systems (Windows, Mac, Linux) and four major interpreters (SpiderMonkey, Rhino, v8, JavaScriptCore). Plus there’s “the browser”, which is a unique environment unto itself. That’s a fair bit of surface area to cover.

Oddly, I think the one of those eight “platforms” with the poorest implementation support is Windows. Most of the CommonJS developers are using Macs or Linux machines, so I’m not sure how much time has really been spent on Windows. I would imagine that JavaScriptCore on Windows is probably the least supported combination.

The good news, however, is that there are projects using all of those JavaScript interpreters and platform compatibility issues will ultimately be ironed out.

CommonJS and the ECMAScript Standard

The CommonJS group is a grassroots effort, and not some formal standards body. In some ways, however, it works like a standards body in that the people working on the standard are also implementing the standard-in-progress and using it to build real applications.

We have no control over the ECMAScript language, which is managed by the TC39 working group. However, there are a few people involved in CommonJS who are part of TC39, and I have firsthand knowledge of others who are keeping an eye on how things are going with CommonJS.

The CommonJS standard-in-progress is designed to work on a subset of ECMAScript 5 that can be made to work on today’s ECMAScript 3 interpreters. ECMAScript 3 is the standard that is running in all of the browsers. In other words, in a CommonJS application you can count on Array.prototype.forEach to be implemented. Obviously, applications can do whatever they want (array destructuring? knock yourself out, but your app will only work on SpiderMonkey and Rhino).

One certainty about CommonJS is that inventing new language syntax is out of scope.

The Module System

The CommonJS group has been remarkably good at avoiding bikeshedding. While there is discussion about names of things, there isn’t heated discussion about it. People are far more interested in issues of functionality and ease-of-use. This is a very good thing, and it allowed us to get modules out of the way early on.

Of course, the lack of bikeshedding doesn’t mean that everyone agrees on things. The CommonJS module system has its controversial aspects, but I think it does well given the constraints:

  1. must work with ES3 syntax (destructuring could actually be useful, but we’re not going to do it)
  2. modules should have self-contained namespaces and be explicit about data the want to export
  3. it should be possible to make modules tamper-proof, though this is not a requirement
  4. using a module should be competitive with using modules in languages like Python and Ruby

TC39 had considered adding modules to ECMAScript 4 and there are module proposals on the table for ECMAScript Harmony that would add some syntax to JavaScript that would look similar to CommonJS modules. Here’s a short module to give you an idea of what CommonJS modules look like:

var sillymath = require("extramath/silly");

exports.addTwo = function(num) {
    return sillymath.add(num, 2);
};

Personally, I find this to be reasonably concise with a nice level of explicitness. Some syntax sugar would be good, and I hope we get that in ES-Harmony. But, this syntax works fine today.

Of course, this syntax is not without controversy. The biggest controversy has been that require() is synchronous – the “extramath/silly” module has to be available as the module above is loaded. However, there are a couple of reasonable ways to deal with this problem and I am happily working with CommonJS modules in the browser which is the environment that is least tolerant to synchronous loading.

Controversy or not, this basic module system was ratified last winter and has been implemented on all target environments of CommonJS.

Discussion is ongoing for a tie-in to the module standard: the module transport standard. Without additional help from the browser or some additional scaffolding running in the page, the module syntax above doesn’t work via a