How is your Time Porfolio? Staying Healthy and Sane in Tech #newtwitter, IE9, and the change in user experience expectations
Sep 11

CommonJS: Bridging client and server, and why JavaScript desperately needs first class modules

JavaScript, Tech Add comments

millenium bridge

(function(require, exports) {
  "use strict";
  // ...
  exports.x = 21;
}).apply({}, typeof require === 'function' ? [require, exports] :
               [function(g){return function(id){return g[id];};}(this._modules = this._modules || {}),
                this._modules['example/foo'] = {}]);

Ouch. This is one of many variants of boilerplate hacks that folks are using to get CommonJS modules playing nicely with browsers. The CommonJS list has been sparked by the question of client vs. server, and how to deal with the two worlds.

First, “Mark Miller has posted a recommendation on the TC39 wiki for CommonJS module boilerplate that permits modules to be crafted for use as <script>”.

And, then we have Kris Zyp’s proposal for an asynchronous module definition “based on the ideas from Transport/C and recent changes discussed.”

There seem to by two high order bits:

What is the focus of CommonJS?

The project started as “ServerJS”, and many server side JS folks started discussions. However, then other browser JS lib folk got into the mix. Folks who deeply care about module systems for the client as well as the server.

There are varying degrees of interop here. On the one hand folks want to be able to have the work that “makes Foo a module” work in both contexts. But further down we run into issues like: how does legacy code work? Do you have to wrap it? How? And finally, the browser needs to be able to load code asynchronously whereas the server doesn’t have the same issue.

Node is taking off like wild fire. Should Ryan be stopping to think about the browser? Does he really care? Or is he more focused on making a great event driven server environment that uses JavaScript?

What common libraries should we be creating as part of the “SDK” of JavaScript so to speak?

How do we hack on support :/

When we get into the “how” it gets messy quick. Messy can be hand-waved away if you assume that everyone will be using build tools and the like, but a ground swell of comments have been about the developer ergonomics of working on projects. How is it to debug and write applications? Do you get the basics: correct line numbers, no need to run builds all the time, etc? And then there is the performance aspect of the final production code.

All of this has just shown me how desperately we need a first class concept of a module beyond the client-esque “script” and function wrappers. Could you imagine showing the apply() code from above to a Java programmer? “Erm, you can’t just import?”

ES4 tried to give us programming units, packages, and namespaces. How about ES.next giving us one simple system to get us out of this CommonJS mess?

4 Responses to “CommonJS: Bridging client and server, and why JavaScript desperately needs first class modules”

  1. J Chris A Says:

    We’ve been doing a lot of brower / server CommonJS code in the CouchDB and CouchApp projects.

    Here is an example of a CommonJS module that is used on both the client and the server of my CouchApp Twitter client. (This is app-specific code, but I also tend to use Mustache.js in CommonJS form on both the client and in CouchDB show and list functions.)

    Module:
    http://github.com/jchris/twebz/blob/master/lib/twebz.js

    In the Node.js async job handler:
    http://github.com/jchris/twebz/blob/master/node/twebzbot.js#L23

    In the browser:
    http://github.com/jchris/twebz/blob/master/evently/profile/profileReady/selectors/div.controls/setup_user.js#L5

    The CouchApp CommonJS runtime is interesting because it preloads all the application code when the page is launched, from the CouchDB design document. Then the require function can be used to selectively load modules.

    I’ve definitely gotten addicted to the peace of mind that comes from knowing that requiring a module won’t effect my other code, or litter the window object with new references.

  2. Ben Gerrissen Says:

    The thing about using code on both server side and client side has another dimension to it I rarely see discussed. In the wrong hands (and this is quite common tbh) one could end up with business logic or sensitive data (user info) on the client side when code is shared cross platform indiscriminatly. Is everyone overlooking this due to the excitement of code working both ends or doesn’t anyone care about the dangerous implications?

    That said, like James Burke I’ve been working on a client side module loader (think we started at the same time but his was a lot simpler). After seeing his API I simplified mine as well and read the CommonJS specs.

    There’s a ‘module’ namespace there which could be used to define modules rather then just hold some data.

    module(function(exp, req){ /* code */ });

    Here’s my client side version of it (still beta) http://github.com/bgerrissen/modulejs

    It uses fn.toString() so it can be parsed looking for what to ‘require’, loads that first and then fires the fn passed to ‘module();’. The parser I wrote is currently quite simplistic and should be expanded to something more elaborate, but the proof of concept is on the table. James Burke came up with require.def(); which is similar but passing the require strings is made mandatory.

    It also seems both James Burke and me came up with a .run() method about the same time (I used it for JSoo) and not sure why he abandoned it, but it’s a great way to kickstart modules into life.

    module.run(’myApp’); // load myApp.js, it’s dependencies and run it.

    Explicit code invocation should really be a feature of CommonJS as well and when looking at this in depth could make require in Ryan Dahl’s NodeJS async as well.

  3. Kevin Dangoor Says:

    I have always contended that there are reasonable ways to make CommonJS modules work in the browser. They’re not perfect or as simple as adding a script tag, but they make for a module system that compares reasonably with that of, for example, Python.

    I certainly hope that TC39 gives us native module support in ECMAScript Harmony. With bult-in syntax, we can have modules that load simply and have synchronous imports that don’t block the browser.

    In my view, no one should have to write a transport format and there are plenty of ways to load modules that provide correct line numbers, good performance, etc.

    I have always been in favor of a common transport format, but never in favor of authoring in that style.

    Kevin

  4. Alex Russell Says:

    The lack of any real attention to async loading from the CommonJS camp dooms it. It’s just “ServerJS” until they get on board with what browsers need. In any case, I don’t have a lot of hope that they’ll be the ones to solve it. Browsers need to step up and bless this with syntax. The Simple Modules proposal is the best I’ve seen yet:

    http://wiki.ecmascript.org/doku.php?id=strawman:simple_modules

    Regards

Leave a Reply

Spam is a pain, I am sorry to have to do this to you, but can you answer the question below?

Q: Type in the word 'cricket'