You are on page 1of 24

11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo

1/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
uddyosmunI.com
Writing Modular JavaScript With AMD,
CommonJS & ES Harmon
TweeL
Modularit The Importance Of Decoupling Your Application
WIen we suy un uppIIcuLIon Is modular, we generuIIy meun IL's composed oI u seL oI IIgIIy decoupIed,
dIsLIncL pIeces oI IuncLIonuIILy sLored In moduIes. As you probubIy know, Ioose coupIIng IucIIILuLes eusIer
muInLuInubIIILy oI upps by removIng dependencie wIere possIbIe. WIen LIIs Is ImpIemenLed eIIIcIenLIy,
ILs quILe eusy Lo see Iow cIunges Lo one purL oI u sysLem muy uIIecL unoLIer.
UnIIke some more LrudILIonuI progrummIng Iunguuges Iowever, LIe currenL ILeruLIon oI JuvuScrIpL
(ECMA-z6z) doesn'L provIde deveIopers wILI LIe meuns Lo ImporL sucI moduIes oI code In u cIeun,
orgunIzed munner. L's one oI LIe concerns wILI specIIIcuLIons LIuL Iuven'L requIred greuL LIougIL unLII
more recenL yeurs wIere LIe need Ior more orgunIzed JuvuScrIpL uppIIcuLIons becume uppurenL.
nsLeud, deveIopers uL presenL ure IeIL Lo IuII buck on vurIuLIons oI LIe moduIe or objecL IILeruI puLLerns.
WILI muny oI LIese, moduIe scrIpLs ure sLrung LogeLIer In LIe DOM wILI numespuces beIng descrIbed by
u sIngIe gIobuI objecL wIere IL's sLIII possIbIe Lo Incur numIng coIIIsIons In your urcIILecLure. TIere's uIso
no cIeun wuy Lo IundIe dependency munugemenL wILIouL some munuuI eIIorL or LIIrd purLy LooIs.
WIIIsL nuLIve soIuLIons Lo LIese probIems wIII be urrIvIng In ES Hurmony, LIe good news Is LIuL wrILIng
moduIur JuvuScrIpL Ius never been eusIer und you cun sLurL doIng IL Loduy.
n LIIs urLIcIe, we're goIng Lo Iook uL LIree IormuLs Ior wrILIng moduIur JuvuScrIpL: AMD, CommonJS
und proposuIs Ior LIe nexL versIon oI JuvuScrIpL, Harmon.
Prelude A Note On Script Loaders
L's dIIIIcuIL Lo dIscuss AMD und CommonJS moduIes wILIouL LuIkIng ubouL LIe eIepIunL In LIe room -
scrIpL Iouders. AL presenL, scrIpL IoudIng Is u meuns Lo u gouI, LIuL gouI beIng moduIur JuvuScrIpL LIuL
cun be used In uppIIcuLIons Loduy - Ior LIIs, use oI u compuLIbIe scrIpL Iouder Is unIorLunuLeIy necessury.
n order Lo geL LIe mosL ouL oI LIIs urLIcIe, recommend guInIng u basic understanding oI Iow
popuIur scrIpL IoudIng LooIs work so LIe expIunuLIons oI moduIe IormuLs muke sense In conLexL.
TIere ure u number oI greuL Iouders Ior IundIIng moduIe IoudIng In LIe AMD und CJS IormuLs, buL my
personuI preIerences ure RequIreJS und curI.js. CompIeLe LuLorIuIs on LIese LooIs ure ouLsIde LIe scope oI
11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
2/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
LIIs urLIcIe, buL cun recommend reudIng JoIn Hunn's posL ubouL curI.js und Jumes Burke's
ScrIpLJunkIe posL on RequIreJS.
rom u producLIon perspecLIve, LIe use oI opLImIzuLIon LooIs (IIke LIe RequIreJS opLImIzer) Lo
concuLenuLe scrIpLs Is recommended Ior depIoymenL wIen workIng wILI sucI moduIes. nLeresLIngIy,
wILI LIe AImond AMD sIIm, RequIreJS doesn'L need Lo be roIIed In LIe depIoyed sILe und wIuL you
mIgIL consIder u scrIpL Iouder cun be eusIIy sIIILed ouLsIde oI deveIopmenL.
TIuL suId, Jumes Burke wouId probubIy suy LIuL beIng ubIe Lo dynumIcuIIy Ioud scrIpLs uILer puge Ioud
sLIII Ius ILs use cuses und RequIreJS cun ussIsL wILI LIIs Loo. WILI LIese noLes In mInd, IeL's geL sLurLed.
AM A Iormut Ior Writing Modolur JuvuScript In The Browser
TIe overuII gouI Ior LIe AMD (AsyncIronous ModuIe DeIInILIon) IormuL Is Lo provIde u soIuLIon Ior
moduIur JuvuScrIpL LIuL deveIopers cun use Loduy. L wus born ouL oI Dojo's reuI worId experIence usIng
XHR+evuI und proponenLs oI LIIs IormuL wunLed Lo uvoId uny IuLure soIuLIons suIIerIng Irom LIe
weuknesses oI LIose In LIe pusL.
TIe AMD moduIe IormuL ILseII Is u proposuI Ior deIInIng moduIes wIere boLI LIe moduIe und
dependencIes cun be usyncIronousIy Iouded. L Ius u number oI dIsLIncL udvunLuges IncIudIng beIng
boLI usyncIronous und IIgIIy IIexIbIe by nuLure wIIcI removes LIe LIgIL coupIIng one mIgIL
commonIy IInd beLween code und moduIe IdenLILy. Muny deveIopers enjoy usIng IL und one couId
consIder IL u reIIubIe sLeppIng sLone Lowurds LIe moduIe sysLem proposed Ior ES Hurmony.
AMD begun us u druIL specIIIcuLIon Ior u moduIe IormuL on LIe CommonJS IIsL buL us IL wusn'L ubIe Lo
reucI IuII concensus, IurLIer deveIopmenL oI LIe IormuL moved Lo LIe umdjs group.
Toduy IL's embruced by projecLs IncIudIng Dojo (1.;), MooTooIs (z.o), Irebug (1.8) und even jQuery
(1.;). AILIougI LIe Lerm CommonJS AMD forma Ius been seen In LIe wIId on occusIon, IL's besL Lo
reIer Lo IL us jusL AMD or Async ModuIe supporL us noL uII purLIcIpunLs on LIe CJS IIsL wIsIed Lo pursue
IL.
Note: TIere wus u LIme wIen LIe proposuI wus reIerred Lo us ModuIes TrunsporLJC, Iowever us LIe spec
wusn'L geured Ior LrunsporLIng exIsLIng CJS moduIes, buL ruLIer, Ior deIInIng moduIes IL mude more
sense Lo opL Ior LIe AMD numIng convenLIon.
Getting Sturted With Modoles
TIe Lwo key concepLs you need Lo be uwure oI Iere ure LIe Ideu oI u define meLIod Ior IucIIILuLIng
moduIe deIInILIon und u reqire meLIod Ior IundIIng dependency IoudIng. define Is used Lo deIIne
numed or unnumed moduIes bused on LIe proposuI usIng LIe IoIIowIng sIgnuLure:
11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
3/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
define(
module_id /*optional*/,
[dependencies] /*optional*/,
definition function /*function for instantiating the module or object*/
);
As you cun LeII by LIe InIIne commenLs, LIe module_id Is un opLIonuI urgumenL wIIcI Is LypIcuIIy onIy
requIred wIen non-AMD concuLenuLIon LooIs ure beIng used (LIere muy be some oLIer edge cuses wIere
IL's useIuI Loo). WIen LIIs urgumenL Is IeIL ouL, we cuII LIe moduIe unonymous.
WIen workIng wILI unonymous moduIes, LIe Ideu oI u moduIe's IdenLILy Is DRY, mukIng IL LrIvIuI Lo
uvoId dupIIcuLIon oI IIIenumes und code. Becuuse LIe code Is more porLubIe, IL cun be eusIIy moved Lo
oLIer IocuLIons (or uround LIe IIIe-sysLem) wILIouL needIng Lo uILer LIe code ILseII or cIunge ILs D. TIe
module_id Is equIvuIenL Lo IoIder puLIs In sImpIe puckuges und wIen noL used In puckuges. DeveIopers
cun uIso run LIe sume code on muILIpIe envIronmenLs jusL by usIng un AMD opLImIzer LIuL works wILI u
CommonJS envIronmenL sucI us r.js.
Buck Lo LIe deIIne sIgnuLure, LIe dependencIes urgumenL represenLs un urruy oI dependencIes wIIcI ure
requIred by LIe moduIe you ure deIInIng und LIe LIIrd urgumenL ('deIInILIon IuncLIon') Is u IuncLIon
LIuL's execuLed Lo InsLunLIuLe your moduIe. A burebone moduIe couId be deIIned us IoIIows:
Undeanding AMD: define()
// A module_id (myModule) is used here for demonstration purposes only
define('myModule',
['foo', 'bar'],
// module definition function
// dependencies (foo and bar) are mapped to function parameters
function ( foo, bar ) {
// return a value that defines the module export
// (i.e the functionality we want to expose for consumption)
// create your module here
var myModule = {
doStuff:function(){
console.log('Yay! Stuff');

11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
4/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
return myModule;
);
// An alternative example could be..
define('myModule',
['math', 'graph'],
function ( math, graph ) {
// Note that this is a slightly different pattern
// With AMD, it's possible to define modules in a few
// different ways due as it's relatively flexible with
// certain aspects of the syntax
return {
plot: function(x, y){
return graph.drawPie(math.randomGrid(x,y));

;
);
reqire on LIe oLIer Iund Is LypIcuIIy used Lo Ioud code In u Lop-IeveI JuvuScrIpL IIIe or wILIIn u moduIe
sIouId you wIsI Lo dynumIcuIIy IeLcI dependencIes. An exumpIe oI ILs usuge Is:
Understanding AMD: require()
// Consider 'foo' and 'bar' are two external modules
// In this example, the 'exports' from the two modules loaded are passed as
// function arguments to the callback (foo and bar)
// so that they can similarly be accessed
require(['foo', 'bar'], function ( foo, bar ) {
// rest of your code here
foo.doSomething();
);
Dnamicall-loaded Dependencies
define(function ( require ) {
var isReady = false, foobar;
11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
5/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
// note the inline require within our module definition
require(['foo', 'bar'], function (foo, bar) {
isReady = true;
foobar = foo() + bar();
);
// we can still return a module
return {
isReady: isReady,
foobar: foobar
;
);
Lnderstunding AM: plogins
The folloing i an eample of defining an AMD-compaible plgin:
// With AMD, it's possible to load in assets of almost any kind
// including text-files and HTML. This enables us to have template
// dependencies which can be used to skin components either on
// page-load or dynamically.
define(['./templates', 'text!./template.md','css!./template.css'],
function( templates, template ){
console.log(templates);
// do some fun template stuff here.

);
Note: Alhogh c! i inclded fo loading CSS dependencie in he aboe eample, i' impoan o
emembe ha hi appoach ha ome caea ch a i no being fll poible o eablih hen he
CSS i fll loaded. Depending on ho o appoach o bild, i ma alo el in CSS being inclded
a a dependenc in he opimied file, o e CSS a a loaded dependenc in ch cae ih caion.
Louding AM Modoles Lsing reqoire.js
require(['app/myModule'],
function( myModule ){
// start the main module which in-turn
// loads other modules
11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
6/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
var module = new myModule();
module.doStuff();
);
Loading AMD Modules Using curl.js
curl(['app/myModule.js'],
function( myModule ){
// start the main module which in-turn
// loads other modules
var module = new myModule();
module.doStuff();
);
Modules With Deferred Dependencies
// This could be compatible with jQuery's Deferred implementation,
// futures.js (slightly different syntax) or any one of a number
// of other implementations
define(['lib/Deferred'], function( Deferred ){
var promise = new Deferred();
require(['lib/templates/?index.html','lib/data/?stats'],
function( template, data ){
promise.resolve({ template: template, data:data );

);
return promise;
);
Wh Is AMD A Better Choice For Writing Modular JavaScript?
Poide a clea popoal fo ho o appoach defining fleible modle.
Significanl cleane han he peen global namepace and <script> ag olion man of
el on. Thee' a clean a o declae and-alone modle and dependencie he ma hae.
Modle definiion ae encaplaed, helping o aoid pollion of he global namepace.
Wok bee han ome alenaie olion (eg. CommonJS, hich e'll be looking a hol).
Doen' hae ie ih co-domain, local o debgging and doen' hae a eliance on ee-
ide ool o be ed. Mo AMD loade ppo loading modle in he boe iho a bild
poce.
Poide a 'anpo' appoach fo inclding mliple modle in a ingle file. Ohe appoache like
CommonJS hae e o agee on a anpo foma.
11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
7/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
L's possIbIe Lo Iuzy Ioud scrIpLs II LIIs Is needed.
AMD Modle Wih Dojo
DeIInIng AMD-compuLIbIe moduIes usIng Dojo Is IuIrIy sLruIgIL-Iorwurd. As per ubove, deIIne uny
moduIe dependencIes In un urruy us LIe IIrsL urgumenL und provIde u cuIIbuck (IucLory) wIIcI wIII
execuLe LIe moduIe once LIe dependencIes Iuve been Iouded. e.g:
define(["dijit/Tooltip"], function( Tooltip ){
//Our dijit tooltip is now available for local use
new Tooltip(...);
);
NoLe LIe unonymous nuLure oI LIe moduIe wIIcI cun now be boLI consumed by u Dojo usyncIronous
Iouder, RequIreJS or LIe sLundurd dojo.requIre() moduIe Iouder LIuL you muy be used Lo usIng.
or LIose wonderIng ubouL moduIe reIerencIng, LIere ure some InLeresLIng goLcIus LIuL ure useIuI Lo
know Iere. AILIougI LIe AMD-udvocuLed wuy oI reIerencIng moduIes decIures LIem In LIe dependency
IIsL wILI u seL oI muLcIIng urgumenLs, LIIs Isn'L supporLed by LIe Dojo 1.6 buIId sysLem - IL reuIIy onIy
works Ior AMD-compIIunL Iouders. e.g:
define(["dojo/cookie", "dijit/Tooltip"], function( cookie, Tooltip ){
var cookieValue = cookie("cookieName");
new Tree(...);
);
TIIs Ius muny udvunces over nesLed numespucIng us moduIes no Ionger need Lo dIrecLIy reIerence
compIeLe numespuces every LIme - uII we requIre Is LIe 'dojoJcookIe' puLI In dependencIes, wIIcI once
uIIused Lo un urgumenL, cun be reIerenced by LIuL vurIubIe. TIIs removes LIe need Lo repeuLedIy Lype ouL
'dojo.' In your uppIIcuLIons.
Noe: AILIougI Dojo 1.6 doesn'L oIIIcIuIIy supporL user-bused AMD moduIes (nor usyncIronous
IoudIng), IL's possIbIe Lo geL LIIs workIng wILI Dojo usIng u number oI dIIIerenL scrIpL Iouders. AL presenL,
uII Dojo core und DIjIL moduIes Iuve been LrunsIormed Lo LIe AMD synLux und Improved overuII AMD
supporL wIII IIkeIy Iund beLween 1.; und z.o.
TIe IInuI goLcIu Lo be uwure oI Is LIuL II you wIsI Lo conLInue usIng LIe Dojo buIId sysLem or wIsI Lo
mIgruLe oIder moduIes Lo LIIs newer AMD-sLyIe, LIe IoIIowIng more verbose versIon enubIes eusIer
mIgruLIon. NoLIce LIuL dojo und dIjIL und reIerenced us dependencIes Loo:
define(["dojo", "dijit", "dojo/cookie", "dijit/Tooltip"], function(dojo, dijit){
var cookieValue = dojo.cookie("cookieName");
11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
8/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
new dijit.Tooltip(...);
);
AMD Modle Deign Paen (Dojo)
If o'e folloed an of m peio po on he benefi of deign paen, o'll kno ha he can
be highl effecie in impoing ho e appoach cing olion o common deelopmen
poblem. John Hann ecenl gae an ecellen peenaion abo AMD modle deign paen
coeing he Singleon, Decoao, Mediao and ohe. I highl ecommend checking o hi lide if
o ge a chance.
Some ample of hee paen can be fond belo:
Decoao paen:
// mylib/UpdatableObservable: a decorator for dojo/store/Observable
define(['dojo', 'dojo/store/Observable'], function ( dojo, Observable ) {
return function UpdatableObservable ( store ) {
var observable = dojo.isFunction(store.notify) ? store :
new Observable(store);
observable.updated = function( object ) {
dojo.when(object, function ( itemOrArray) {
dojo.forEach( [].concat(itemOrArray), this.notify, this );
;
;
return observable; // makes `new` optional
;
);
// decorator consumer
// a consumer for mylib/UpdatableObservable
define(['mylib/UpdatableObservable'], function ( makeUpdatable ) {
var observable, updatable, someItem;
// ... here be code to get or create `observable`
// ... make the observable store updatable
11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
9/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
updatable = makeUpdatable(observable); // `new` is optional!
// ... later, when a cometd message arrives with new data item
updatable.updated(updatedItem);
);
Adapter pattern
// 'mylib/Array' adapts `each` function to mimic jQuery's:
define(['dojo/_base/lang', 'dojo/_base/array'], function (lang, array) {
return lang.delegate(array, {
each: function (arr, lambda) {
array.forEach(arr, function (item, i) {
lambda.call(item, i, item); // like jQuery's each
)

);
);
// adapter consumer
// 'myapp/my-module':
define(['mylib/Array'], function ( array ) {
array.each(['uno', 'dos', 'tres'], function (i, esp) {
// here, `this` == item
);
);
AMD Modules With jQuer
The Basics
Unlike Dojo, jQuer reall onl comes with one file, however given the plugin-based nature of the
librar, we can demonstrate how straight-forward it is to define an AMD module that uses it below.
define(['js/jquery.js','js/jquery.color.js','js/underscore.js'],
function($, colorPlugin, _){
// Here we've passed in jQuery, the color plugin and Underscore
// None of these will be accessible in the global scope, but we
// can easily reference them below.
11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
10/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
// Pseudo-randomize an array of colors, selecting the first
// item in the shuffled array
var shuffleColor = _.first(_.shuffle(['#666','#333','#111']));
// Animate the background-color of any elements with the class
// 'item' on the page using the shuffled color
$('.item').animate({'backgroundColor': shuffleColor );
return {;
// What we return can be used by other modules
);
TIere Is Iowever someLIIng mIssIng Irom LIIs exumpIe und IL's LIe concepL oI regIsLruLIon.
Registering jQuer As An Asnc-compatible Module
One oI LIe key IeuLures LIuL Iunded In jQuery 1.; wus supporL Ior regIsLerIng jQuery us un usyncIronous
moduIe. TIere ure u number oI compuLIbIe scrIpL Iouders (IncIudIng RequIreJS und curI) wIIcI ure
cupubIe oI IoudIng moduIes usIng un usyncIronous moduIe IormuL und LIIs meuns Iewer Iucks ure
requIred Lo geL LIIngs workIng.
As u resuIL oI jQuery's popuIurILy, AMD Iouders need Lo Luke InLo uccounL muILIpIe versIons oI LIe IIbrury
beIng Iouded InLo LIe sume puge us you IdeuIIy don'L wunL severuI dIIIerenL versIons IoudIng uL LIe sume
LIme. ouders Iuve LIe opLIon oI eILIer specIIIcuIIy LukIng LIIs Issue InLo uccounL or InsLrucLIng LIeIr
users LIuL LIere ure known Issues wILI LIIrd purLy scrIpLs und LIeIr IIbrurIes.
WIuL LIe 1.; uddILIon brIngs Lo LIe LubIe Is LIuL IL IeIps uvoId Issues wILI oLIer LIIrd purLy code on u
puge uccIdenLuIIy IoudIng up u versIon oI jQuery on LIe puge LIuL LIe owner wusn'L expecLIng. You don'L
wunL oLIer InsLunces cIobberIng your own und so LIIs cun be oI beneIIL.
TIe wuy LIIs works Is LIuL LIe scrIpL Iouder beIng empIoyed IndIcuLes LIuL IL supporLs muILIpIe jQuery
versIons by specIIyIng LIuL u properLy, define.amd.jQuery Is equuI Lo Lrue. or LIose InLeresLed In
more specIIIc ImpIemenLuLIon deLuIIs, we regIsLer jQuery us u numed moduIe us LIere Is u rIsk LIuL IL cun
be concuLenuLed wILI oLIer IIIes wIIcI muy use AMD's define() meLIod, buL noL use u proper
concuLenuLIon scrIpL LIuL undersLunds unonymous AMD moduIe deIInILIons.
TIe numed AMD provIdes u suIeLy bIunkeL oI beIng boLI robusL und suIe Ior mosL use-cuses.
// Account for the existence of more than one global
// instances of jQuery in the document, cater for testing
11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
11/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
// .noConflict()
var jQuery = this.jQuery "jQuery",
$ = this.$ "$",
originaljQuery = jQuery,
original$ = $,
amdDefined;
define(['jquery'] , function ($)
$('.items').css('background','green');
return function () ;
);
// The very easy to implement flag stating support which
// would be used by the AMD loader
define.amd =
jQuery: true
;
Smarter jQuer Plugins
've recenLIy dIscussed some Ideus und exumpIes oI Iow jQuery pIugIns couId be wrILLen usIng UnIversuI
ModuIe DeIInILIon (UMD) puLLerns Iere. UMDs deIIne moduIes LIuL cun work on boLI LIe cIIenL und
server, us weII us wILI uII popuIur scrIpL Iouders uvuIIubIe uL LIe momenL. WIIIsL LIIs Is sLIII u new ureu
wILI u IoL oI concepLs sLIII beIng IInuIIzed, IeeI Iree Lo Iook uL LIe code sumpIes In LIe secLIon LILIe AMD
&& CJS beIow und IeL me know II you IeeI LIere's unyLIIng we couId do beLLer.
What Script Loaders & Frameworks Support AMD?
n-browser:
Server-side:
RequIreJS ILLp:JJrequIrejs.org
PN ILLp:JJgILIub.comJpInIJIouder-js
AMD Conclusions
TIe ubove ure very LrIvIuI exumpIes oI jusL Iow useIuI AMD moduIes cun LruIy be, buL LIey IopeIuIIy
provIde u IounduLIon Ior undersLundIng Iow LIey work.
You muy be InLeresLed Lo know LIuL muny vIsIbIe Iurge uppIIcuLIons und compunIes currenLIy use AMD
11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
12/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
modle a a pa of hei achiece. Thee inclde IBM and he BBC iPlae, hich highligh j
ho eiol hi foma i being conideed b deelope a an enepie-leel.
Fo moe eaon h man deelope ae oping o e AMD modle in hei applicaion, o ma
be ineeed in hi po b Jame Bke.
CommonJS A Module Format Optimied For The Server
CommonJS ae a olnee oking gop hich aim o deign, poope and andadie JaaScip
API. To dae he'e aemped o aif andad fo boh modle and package. The CommonJS
modle popoal pecifie a imple API fo declaing modle ee-ide and nlike AMD aemp o
coe a boade e of concen ch a io, fileem, pomie and moe.
Getting Started
Fom a ce pepecie, a CJS modle i a eable piece of JaaScip hich epo pecific
objec made aailable o an dependen code - hee ae picall no fncion appe aond ch
modle (o o on' ee define ed hee fo eample).
A a high-leel he baicall conain o pima pa: a fee aiable named exports hich
conain he objec a modle ihe o make aailable o ohe modle and a require fncion ha
modle can e o impo he epo of ohe modle.
Understanding CJS: require() and exports
// package/lib is a dependency we require
var lib = require('package/lib');
// some behaviour for our module
function foo(){
lib.log('hello world!');

// export (expose) foo to other modules


exports.foo = foo;
Basic consumption of exports
// define more behaviour we would like to expose
function foobar(){
this.foo = function(){
11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
13/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
console.log('Hello foo');

this.bar = function(){
console.log('Hello bar');

// expose foobar to other modules


exports.foobar = foobar;
// an application consuming 'foobar'
// access the module relative to the path
// where both usage and module files exist
// in the same directory
var foobar = require('./foobar').foobar,
test = new foobar();
test.bar(); // 'Hello bar'
AMD-equivalent Of The First CJS Eample
define(['package/lib'], function(lib){
// some behaviour for our module
function foo(){
lib.log('hello world!');

// export (expose) foo for other modules
return {
foobar: foo
;
);
Consuming Multiple Dependencies
app.js
11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
14/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
var modA = require('./foo');
var modB = require('./bar');
exports.app = function(){
console.log('Im an application!');

exports.foo = function(){
return modA.helloWorld();

ba.j
exports.name = 'bar';
foo.j
require('./bar');
exports.helloWorld = function(){
return 'Hello World!!''

Wha Loade & Fameok Sppo CJS?


In-boe:
See-ide:
I CJS Siable Fo The Boe?
Thee ae deelope ha feel CommonJS i bee ied o ee-ide deelopmen hich i one eaon
hee' cenl a leel of diageemen oe hich foma hold and ill be ed a he de faco
andad in he pe-Hamon age moing foad. Some of he agmen again CJS inclde a noe
ha man CommonJS API adde ee-oiened feae hich one old impl no be able o
implemen a a boe-leel in JaaScip - fo eample, io, sstem and js cold be conideed
nimplemenable b he nae of hei fncionali.
Tha aid, i' efl o kno ho o ce CJS modle egadle o ha e can bee appeciae
ho he fi in hen defining modle hich ma be ed eehee. Modle hich hae
applicaion on boh he clien and ee inclde alidaion, coneion and emplaing engine. The
a ome deelope ae appoaching chooing hich foma o e i oping fo CJS hen a modle
can be ed in a ee-ide enionmen and ing AMD if hi i no he cae.
A AMD modle ae capable of ing plgin and can define moe ganla hing like conco and
fncion hi make ene. CJS modle ae onl able o define objec hich can be edio o ok
ih if o'e ing o obain conco o of hem.
11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
15/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
AILIougI IL's beyond LIe scope oI LIIs urLIcIe, you muy Iuve uIso noLIced LIuL LIere were dIIIerenL Lypes
oI 'requIre' meLIods menLIoned wIen dIscussIng AMD und CJS.
TIe concern wILI u sImIIur numIng convenLIon Is oI course conIusIon und LIe communILy ure currenLIy
spIIL on LIe merILs oI u gIobuI requIre IuncLIon. JoIn Hunn's suggesLIon Iere Is LIuL ruLIer LIun cuIIIng IL
'requIre', wIIcI wouId probubIy IuII Lo ucIIeve LIe gouI oI InIormIng users ubouL LIe dIIIerenL beLween u
gIobuI und Inner requIre, IL muy muke more sense Lo renume LIe gIobuI Iouder meLIod someLIIng eIse
(e.g. LIe nume oI LIe IIbrury). L's Ior LIIs reuson LIuL u Iouder IIke curI.js uses curl() us opposed Lo
require.
AMD && CommonJS Competing, But Equall Valid Standards
WIIIsL LIIs urLIcIe Ius pIuced more empIusIs on usIng AMD over CJS, LIe reuIILy Is LIuL boLI IormuLs ure
vuIId und Iuve u use.
AMD udopLs u browser-IIrsL upproucI Lo deveIopmenL, opLIng Ior usyncIronous beIuvIour und sImpIIIIed
buckwurds compuLubIIILy buL IL doesn'L Iuve uny concepL oI IIe JO. L supporLs objecLs, IuncLIons,
consLrucLors, sLrIngs, JSON und muny oLIer Lypes oI moduIes, runnIng nuLIveIy In LIe browser. L's
IncredIbIy IIexIbIe.
CommonJS on LIe oLIer Iund Lukes u server-IIrsL upproucI, ussumIng syncIronous beIuvIour, no
gIobuI baae us JoIn Hunn wouId reIer Lo IL us und IL uLLempLs Lo cuLer Ior LIe IuLure (on LIe server).
WIuL we meun by LIIs Is LIuL becuuse CJS supporLs unwrupped moduIes, IL cun IeeI u IILLIe more cIose Lo
LIe ES.nexLJHurmony specIIIcuLIons, IreeIng you oI LIe define() wrupper LIuL AMD enIorces. CJS
moduIes Iowever onIy supporL objecLs us moduIes.
AILIougI LIe Ideu oI yeL unoLIer moduIe IormuL muy be duunLIng, you muy be InLeresLed In some
sumpIes oI work on IybrId AMDJCJS und UnIveruI AMDJCJS moduIes.
Basic AMD Hbrid Format (John Hann)
define( function (require, exports, module){
var shuffler = require('lib/shuffle');
exports.randomize = function( input ){
return shuffler.shuffle(input);

);
AMD/CommonJS Universal Module Definition (Variation 2, UMDjs)
11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
16/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
/**
* exports object based version, if you need to make a
* circular dependency or need compatibility with
* commonjs-like environments that are not Node.
*/
(function (define) {
//The 'id' is optional, but recommended if this is
//a popular web library that is used mostly in
//non-AMD/Node environments. However, if want
//to make an anonymous module, remove the 'id'
//below, and remove the id use in the define shim.
define('id', function (require, exports) {
//If have dependencies, get them here
var a = require('a');
//Attach properties to exports.
exports.name = value;
);
(typeof define === 'function' && define.amd ? define : function (id, factory) {
if (typeof exports !== 'undefined') {
//commonjs
factory(require, exports);
else {
//Create a global function. Only works if
//the code does not have dependencies, or
//dependencies fit the call pattern below.
factory(function(value) {
return window[value];
, (window[id] = {));

));
Etensible UMD Plugins With (Variation b mself and Thomas Davis).
core.js
// Module/Plugin core
// Note: the wrapper code you see around the module is what enables
// us to support multiple module formats and specifications by
// mapping the arguments defined to what a specific format expects
// to be present. Our actual module functionality is defined lower
// down, where a named module and exports are demonstrated.
11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
17/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
;(function ( name, definition )
var theModule = definition(),
// this is considered "safe":
hasDefine = typeof define === 'function' && define.amd,
// hasDefine = typeof define === 'function',
hasExports = typeof module !== 'undefined' && module.exports;
if ( hasDefine ) // AMD Module
define(theModule);
else if ( hasExports ) // Node.js Module
module.exports = theModule;
else // Assign to common namespaces or simply the global object (window)
(this.jQuery this.ender this.$ this)[name] = theModule;

)( 'core', function ()
var module = this;
module.plugins = [];
module.highlightColor = "yellow";
module.errorColor = "red";
// define the core module here and return the public API
// this is the highlight method used by the core highlightAll()
// method and all of the plugins highlighting elements different
// colors
module.highlight = function(el,strColor)
// this module uses jQuery, however plain old JavaScript
// or say, Dojo could be just as easily used.
if(this.jQuery)
jQuery(el).css('background', strColor);

return
highlightAll:function()
module.highlight('div', module.highlightColor);

;
);
mEtension.js
;(function ( name, definition )
11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
18/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
var theModule = definition(),
hasDefine = typeof define === 'function',
hasExports = typeof module !== 'undefined' && module.exports;
if ( hasDefine ) // AMD Module
define(theModule);
else if ( hasExports ) // Node.js Module
module.exports = theModule;
else // Assign to common namespaces or simply the global object (window)
// account for for flat-file/global module extensions
var obj = null;
var namespaces = name.split(".");
var scope = (this.jQuery this.ender this.$ this);
for (var i = 0; i
app.j
$(function()
// the plugin 'core' is exposed under a core namespace in
// this example which we first cache
var core = $.core;
// use then use some of the built-in core functionality to
// highlight all divs in the page yellow
core.highlightAll();
// access the plugins (extensions) loaded into the 'plugin'
// namespace of our core module:
// Set the first div in the page to have a green background.
core.plugin.setGreen("div:first");
// Here we're making use of the core's 'highlight' method
// under the hood from a plugin loaded in after it
// Set the last div to the 'errorColor' property defined in
// our core module/plugin. If you review the code further down
// you'll see how easy it is to consume properties and methods
// between the core and other plugins
core.plugin.setRed('div:last');
);
11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
19/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
ES Harmon Modules Of The Future
TC39, he andad bod chaged ih defining he na and emanic of ECMAScip
and i fe ieaion i compoed of a nmbe of e inelligen deelope. Some
of hee deelope (ch a Ale Rell) hae been keeping a cloe ee on he
eolion of JaaScip age fo lage-cale deelopmen oe he pa fe ea and
ae acel aae of he need fo bee langage feae fo iing moe modla
JS.
Fo hi eaon, hee ae cenl popoal fo a nmbe of eciing addiion o
he langage inclding fleible modle ha can ok on boh he clien and ee, a
modle loade and moe. In hi ecion, I'll be hoing o ome code ample of he
na fo modle in ES.ne o o can ge a ae of ha' o come.
Note: Alhogh Hamon i ill in he popoal phae, o can alead o
(paial) feae of ES.ne ha adde naie ppo fo iing modla
JaaScip hank o Google' Tace compile. To ge p and nning ih Tace in
nde a mine, ead hi geing aed gide. Thee' alo a JSConf peenaion
abo i ha' oh looking a if o'e ineeed in leaning moe abo he
pojec.
Modules With Imports And Eports
If o'e ead hogh he ecion on AMD and CJS modle o ma be familia ih
he concep of modle dependencie (impo) and modle epo (o, he pblic
API/aiable e allo ohe modle o conme). In ES.ne, hee concep hae been
popoed in a lighl moe ccinc manne ih dependencie being pecified ing an
11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
20/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
import keyword. export isn't greatly different to what we might expect and I think
many developers will look at the code below and instantly 'get' it.
import declaaion bind a modle' epo a local aiable and ma be enamed o aoid name
colliion/conflic.
eport declaaion declae ha a local-binding of a modle i eenall iible ch ha ohe
modle ma ead he epo b can' modif hem. Ineeingl, modle ma epo child
modle hoee can' epo modle ha hae been defined elehee. Yo ma alo ename
epo o hei eenal name diffe fom hei local name.
module staff{
// specify (public) exports that can be consumed by
// other modules
export var baker = {
bake: function( item ){
console.log('Woo! I just baked ' + item);

module skills{
export var specialty = "baking";
export var experience = "5 years";

module cakeFactory{
// specify dependencies
import baker from staff;
// import everything with wildcards
import * from skills;
export var oven = {
makeCupcake: function( toppings ){
baker.bake('cupcake', toppings);
,
makeMuffin: function( mSize ){
11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
21/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
baker.bake('muffin', size);

Modle Loaded Fom Remoe Soce


The modle popoal alo cae fo modle hich ae emoel baed (e.g. a hid-pa API appe)
making i impliic o load modle in fom eenal locaion. Hee' an eample of plling in he
modle e defined aboe and iliing i:
module cakeFactory from 'http://addyosmani.com/factory/cakes.js';
cakeFactory.oven.makeCupcake('sprinkles');
cakeFactory.oven.makeMuffin('large');
Modle Loade API
The modle loade popoed decibe a dnamic API fo loading modle in highl conolled cone.
Signae ppoed on he loade inclde load( url, moduleInstance, error) fo loading
modle, createModule( object, globalModuleReferences) and ohe. Hee' anohe
eample of dnamicall loading in he modle e iniiall defined. Noe ha nlike he la eample
hee e plled in a modle fom a emoe oce, he modle loade API i bee ied o dnamic
cone.
Loader.load('http://addyosmani.com/factory/cakes.js',
function(cakeFactory){
cakeFactory.oven.makeCupcake('chocolate');
);
CommonJS-like Modle Fo The See
Fo deelope ho ae ee-oiened, he modle em popoed fo ES.ne in' j conained o
looking a modle in he boe. Belo fo eample, o can ee a CJS-like modle popoed fo e
on he ee:
// io/File.js
export function open(path) { ... ;
export function close(hnd) { ... ;
// compiler/LexicalHandler.js
module file from 'io/File';
11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
22/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
import { open, close from file;
export function scan(in) {
try {
var h = open(in) ...

finally { close(h)

module lexer from 'compiler/LexicalHandler';


module stdlib from '@std';
//... scan(cmdline[0]) ...
Clae Wih Conco, Gee & See
The noion of a cla ha ala been a conenio ie ih pi and e'e o fa go along ih
eihe falling back on JaaScip' poopal nae o hogh ing fameok o abacion ha
offe he abili o e cla definiion in a fom ha dega o he ame poopal behaio.
In Hamon, clae come a pa of he langage along ih conco and (finall) ome ene of
e piac. In he folloing eample, I'e inclded ome inline commen o help o ndeand
ho clae ae ced, b o ma alo noice he lack of he od 'fncion' in hee. Thi in' a
po eo: TC39 hae been making a concio effo o deceae o abe of he function keod
fo eehing and he hope i ha hi ill help implif ho e ie code.
class Cake{
// We can define the body of a class' constructor
// function by using the keyword 'constructor' followed
// by an argument list of public and private declarations.
constructor( name, toppings, price, cakeSize ){
public name = name;
public cakeSize = cakeSize;
public toppings = toppings;
private price = price;

// As a part of ES.next's efforts to decrease the unnecessary


// use of 'function' for everything, you'll notice that it's
// dropped for cases such as the following. Here an identifier
11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
23/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
// followed by an argument list and a body defines a new method
addTopping( topping ){
public(this).toppings.push(topping);

// Getters can be defined by declaring get before


// an identifier/method name and a curly body.
get allToppings(){
return public(this).toppings;

get qualifiesForDiscount(){
return private(this).price > 5;

// Similar to getters, setters can be defined by using


// the 'set' keyword before an identifier
set cakeSize( cSize ){
if( cSize
ES Harmon Conclusions
As you can see, ES.next is coming with some exciting new additions. Although Traceur
can be used to an extent to try our such features in the present, remember that it may
not be the best idea to plan out your system to use Harmony (just yet). There are
risks here such as specifications changing and a potential failure at the cross-
browser level (IE9 for example will take a while to die) so your best bets until we
have both spec finalization and coverage are AMD (for in-browser modules) and CJS (for
those on the server).
Conclusions And Further Reading:
11/24/11 Writing Modular JavaScript With AMD, CommonJS & ES Harmony addyo
24/24 www.readability.com/articles/ummplmts?legacy_bookmarklet=1#
Ad ha' i f . If hae fhe ei ab a f he ic ceed
da, fee fee hi e ie ad I' d be he!
The echica eie f hi aice a dig ig Diig (f Gge Che). Diig
i a fee ha a add bh ce ad highigh a ie
dce he eb ad if hee ae ceci eei d ie
gge, eae e eihe Diig ( a GiHb gi) ad I' d e adde a
i ed e.
Cigh Add Oai, 2011. A Righ Reeed.
Oiginal URL:
http://addosmani.com/writing-modular-js/
Shae hi aicle

You might also like