Based my blog post yesterday
"More on why AMD is Not the Answer",
you might guess I'm an AMD-hater. I strive to
not be negative,
but sometimes I fail. Mea culpa.
I do have a number of issues with AMD. But I think it's also fair to
point out "the good parts".
my background
I've only really played with a few AMD
libraries/runtimes. I've been more fiddling around with ways of
taking node/CommonJS-style modules, and making them
consumable by AMD runtimes. The AMD runtimes I've played with
the most are
almond
and (my own)
modjewel.
My focus has been on just the raw require()
and define()
functions.
But I follow a lot of the AMD chatter around the web,
and have done at least reading and perusing through other
AMD implementations. To find implementations of AMD, look at
this list
and search for "async". The ones I hear the most about are
require.js,
Dojo,
PINF,
and
curl.
And now, "the good parts".
the code
Browsing the source repositories and web sites,
you'll note that folks have spent a
lot of time on the libraries - the code itself, documentation,
test suites, support, etc. Great jobs, all. I know a lot
of these libraries have been battle-tested by folks in
positions to do pretty good battle-testing with them.
the evangelism
Special mention here to
James Burke
(not
this one),
who has done a spectacular job leading and evangelizing
the AMD cause, both within the "JavaScript Module"
community, and outside. In particular, he's been
trying to get AMD support into popular libraries like
jQuery,
backbone,
underscore and
node.js.
Sometimes with success, sometimes not. James has been
cool and collected when dealing with jerks like me,
pestering him with complaints, questions, requests and bug reports.
Some open source communities can be cold and bitter
places, but the AMD community is not one of those, and I'm sure
that's in part due to James.
Thanks for all your hard work James!
the async support
AMD is an acronym for
Asynchronous Module Definition.
That first word, Asynchronous, is key.
For the most part, if you're using JavaScript, you're living in a world of
single-threaded processing, where long-running functions are implemented as
asynchronous calls that take
callback functions as arguments. It makes sense, at least in some cases,
to extend this to the function of loading JavaScript code.
If you need to load JavaScript in an async fashion, AMD is designed for you,
and uses existing async function patterns that
JavaScript programmers should already be familiar with.
support for CommonJS
This is a touchy subject, because when you ask 10 people what "CommonJS" is,
you'll get 15 different answers. For the purposes here, and really whenever
I use the phrase "CommonJS", I'm technically referring to
one of the Modules/1.x specifications,
and more specifically, the general definitions of the require()
function
and the exports
and module
variables used in the body of a module.
These general definitions are also applicable, with some differences, in
node.js.
When I use the phrase "CommonJS", I am NEVER referring to
the other specifications in the CommonJS specs stable (linked to above).
AMD supports this general definition of "CommonJS", in my book.
Super double plus one good!
Aside: I'm looking for another 'name' to call my simplistic notion
of CommonJS. So far, things like simple require()
y support,
seem to capture my intent. But you know how
bad I am with naming.
the design for quick edit-debug cycles
One of the goals of AMD is to facilitate a quick
edit-debug cycle while you are working on your JavaScript. To
do this, AMD specifies that you wrap the body of your module in
a specific type of function wrapper when you author it.
Because of the way it's designed, these JavaScript files can
be loaded directly with a <script src=>
element in your HTML
file, or via <script src=>
elements injected into your live web page
dynamically, by a library. This means that as soon as you save the JavaScript you're
editing in your text editor/IDE, you can refresh the page in
your browser without an intervening "build step" or special
server processing - the same files you are editing are loaded
directly in the browser.
the resources
Beyond just loading JavaScript code, AMD supports the notion
of loading other things. The things you can load
are determined by what
Loader Plugins
you have available. Examples include:
Coming from the Java world, this is familiar territory; see:
Class.getResource*() methods.
For the most part, I consider this to be amongst the core bits of
functionality that a programming library should provide. It's a common
pattern to ship data with your code, and you need some way to access it.
And, of course, this resource loading is available in an async manner
with AMD.
Aside: I'm not sure what the analog of this is in the node.js world.
You can certainly do it by hand, making use of the
__dirname
global, and then performing i/o yourself. I'm just not sure if
someone has wrapped this up nicely in a library yet.
the build
At the end of the day, hopefully, your web application is going to be available
to some audience, who will be using it for realz. It's unlikely that you will want to
continue to load your JavaScript code (and resources) as individual pieces as you do
in development; instead, you'll want to concatenate and minimize your wads of goo
to keep load time to a minimum for your customers.
And it seems like most AMD implementations provide a mechanism to do this.