Monday, November 21, 2011

Tuesday, November 15, 2011

Why not AMD?

This started as a private response to some tweets by Jeremy Ashkenas that indicated some concern around optionally registering code as an AMD JavaScript module, but since his comments were in a public space, it makes sense to post my response in a public space.

His concerns as mentioned in the tweets:
  • Isn't canonical in any JS runtime
  • Inefficient by default
  • Incompatible with JS.next
  • Known temporary solution
Twitter is bad for this kind of conversation, and Jeremy is busy with work, but hopefully he can expand on his concerns at some point if my responses below do not address them.

Isn't canonical in any JS runtime

The goal is to create a grassroots effort based on real, multiple implementations that makes it canonical. I believe it is following the way to get something standardized. There are multiple implementations (requirejs, curl, dojo and mootools), and there are multiple higher level toolkits that register with it: jQuery, Dojo and MooTools.

It is also based on real world experience supporting modular code in the browser. It is informed by Dojo's previous modular experience, and jQuery's needs for modular loading. I believe this places it in a better position than how modules in ES harmony are being designed, particularly since it can be opt-in that works with ES3 grammar.

Node adopted a variation of CommonJS modules, but Node's implementers have been very explicit about not picking up anything else from CommonJS, and they support their own non-conformant extensions, like module.exports. Node is a monoculture and very inward focused, and since it has sync IO, it is not concerned with browser needs.

Even if CommonJS were supported well in the browser today, there still needs to be a way to embed multiple CommonJS modules in a file. AMD is a great candidate for that format -- CommonJS never standardized on a "transport format" for this need.

I expand on this a bit more in the Why AMD document.

Inefficient by default

I assume this means that it allows separate modules to be loaded async. FWIW, the current state of ES harmony modules will allow separate file loading for each module. This works better for debugging.

For AMD, you can get the "one script file at the bottom of the page" loading with the 750 byte almond AMD shim and runtime http loading.

I cannot see a better solution to this issue. If you have ideas I would like to hear them.

Incompatible with JS.next

Since JS.next/ES harmony modules do not have an implementation yet, I am not sure what this means. It still needs at least one good implementation to prove out the API. I think AMD can better inform the ES harmony effort since it has real deployment by web-based JS users, the harder environment to get right.

Also, given that harmony modules uses new syntax and by default there is no global access, I think they are making it very hard to allow existing code to opt in to being a harmony module. I have given David Herman feedback to this effect.

I want to help make any harmony module implementation better based on AMD's real deployment. I go into it more in the aforementioned Why AMD page, but being able to set the exported value to a function, and the use of loader plugins to avoid nested, async callbacks for simple resources are of great value in any module system.

Known temporary solution

As you might gather from the above, I do not see it as a temporary solution. It has more legs than CommonJS modules because it works well in browsers and it can be used as the "transport format" for CommonJS modules.

In addition, unless someone can get Microsoft to adopt rapid IE updates, even for old IEs, AMD will be around for a long time. It is a great transpile target for ES harmony module code that wants to run in older browsers. I am prototyping that effort, although I need to update to a real parser instead of regexps. I have a branch of narcissus that has the core parser/lexer/definitions that will run in ES3 browsers as part of that work.

All things considered, I would rather not work on JS module formats. I want to get on to building useful things for end users. But the CommonJS effort was deficient (but a great first effort given their design goals -- AMD uses a bunch of their work), and I do not think ES harmony modules are there yet. Instead of just complaining, I worked with others to work out something better and got implementations and actual, real adoption.

I'm open to something else that has done the above, but I have not seen it yet. Feel free to offer alternatives and feedback though. I just want to get to a good solution, but I'm also tired of waiting for something magical to fix the problem.

Thursday, November 03, 2011

RequireJS 1.0.1 released

RequireJS 1.0.1 is available for download.

This just has three small bug fixes in it (one in require.js, two in r.js). It was prompted by the release of jQuery 1.7 and wanting to make sure people could use the "namespace" optimizer option with it, now that jQuery 1.7 registers as an AMD module.

The bug fixes were related to:

  • allowing full URLs for simplified CommonJS wrapped modules
  • AST parsing of dependencies for modules that use a variable for the factory function
  • catching more cases that should have the "namespace" optimizer option applied

Detailed list of changes for require.js and the r.js optimizer: