Você está na página 1de 32

6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

WritingModularJavaScriptWith
AMD,CommonJS&ESHarmony
WRITTENBY:ADDYOSMANITECHNICALREVIEW:ANDREHANSSON
WITHSPECIALTHANKSTOJAMESBURKE,JOHNHANNANDTHOMASDAVIS

+350 Recommend this on Google


Tweet

ModularityTheImportanceOfDecouplingYourApplication
Whenwesayanapplicationismodular,wegenerallymeanit'scomposedofasetofhighly
decoupled,distinctpiecesoffunctionalitystoredinmodules.Asyouprobablyknow,loose
couplingfacilitateseasiermaintainabilityofappsbyremovingdependencieswherepossible.
Whenthisisimplementedeciently,itsquiteeasytoseehowchangestoonepartofa
systemmayaectanother.

Unlikesomemoretraditionalprogramminglanguageshowever,thecurrentiterationof
JavaScript(ECMA262)doesn'tprovidedeveloperswiththemeanstoimportsuchmodules
ofcodeinaclean,organizedmanner.It'soneoftheconcernswithspecicationsthat
haven'trequiredgreatthoughtuntilmorerecentyearswheretheneedformoreorganized
JavaScriptapplicationsbecameapparent.

Instead,developersatpresentarelefttofallbackonvariationsofthemoduleorobject
literalpatterns.Withmanyofthese,modulescriptsarestrungtogetherintheDOMwith
namespacesbeingdescribedbyasingleglobalobjectwhereit'sstillpossibletoincur

https://addyosmani.com/writingmodularjs/ 1/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

namingcollisionsinyourarchitecture.There'salsonocleanwaytohandledependency
managementwithoutsomemanualeortorthirdpartytools.

WhilstnativesolutionstotheseproblemswillbearrivinginESHarmony,thegoodnewsis
thatwritingmodularJavaScripthasneverbeeneasierandyoucanstartdoingittoday.

Inthisarticle,we'regoingtolookatthreeformatsforwritingmodularJavaScript:AMD,
CommonJSandproposalsforthenextversionofJavaScript,Harmony.

PreludeANoteOnScriptLoaders
It'sdiculttodiscussAMDandCommonJSmoduleswithouttalkingabouttheelephantin
theroomscriptloaders.Atpresent,scriptloadingisameanstoagoal,thatgoalbeing
modularJavaScriptthatcanbeusedinapplicationstodayforthis,useofacompatible
scriptloaderisunfortunatelynecessary.Inordertogetthemostoutofthisarticle,I
recommendgainingabasicunderstandingofhowpopularscriptloadingtoolsworksothe
explanationsofmoduleformatsmakesenseincontext.

ThereareanumberofgreatloadersforhandlingmoduleloadingintheAMDandCJS
formats,butmypersonalpreferencesareRequireJSandcurl.js.Completetutorialsonthese
toolsareoutsidethescopeofthisarticle,butIcanrecommendreadingJohnHann'spost
aboutcurl.jsandJamesBurke'sRequireJSAPIdocumentationformore.

Fromaproductionperspective,theuseofoptimizationtools(liketheRequireJSoptimizer)
toconcatenatescriptsisrecommendedfordeploymentwhenworkingwithsuchmodules.
Interestingly,withtheAlmondAMDshim,RequireJSdoesn'tneedtoberolledinthe
deployedsiteandwhatyoumightconsiderascriptloadercanbeeasilyshiftedoutsideof
development.

Thatsaid,JamesBurkewouldprobablysaythatbeingabletodynamicallyloadscriptsafter
pageloadstillhasitsusecasesandRequireJScanassistwiththistoo.Withthesenotesin
mind,let'sgetstarted.

https://addyosmani.com/writingmodularjs/ 2/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

AMDAFormatForWritingModularJavaScriptInTheBrowser
TheoverallgoalfortheAMD(AsynchronousModuleDenition)formatistoprovidea
solutionformodularJavaScriptthatdeveloperscanusetoday.ItwasbornoutofDojo'sreal
worldexperienceusingXHR+evalandproponentsofthisformatwantedtoavoidanyfuture
solutionssueringfromtheweaknessesofthoseinthepast.

TheAMDmoduleformatitselfisaproposalfordeningmoduleswhereboththemodule
anddependenciescanbeasynchronouslyloaded.Ithasanumberofdistinctadvantages
includingbeingbothasynchronousandhighlyexiblebynaturewhichremovesthetight
couplingonemightcommonlyndbetweencodeandmoduleidentity.Manydevelopers
enjoyusingitandonecouldconsideritareliablesteppingstonetowardsthemodulesystem
proposedforESHarmony.

AMDbeganasadraftspecicationforamoduleformatontheCommonJSlistbutasit
wasn'tabletoreachfullconcensus,furtherdevelopmentoftheformatmovedtotheamdjs
group.

Todayit'sembracedbyprojectsincludingDojo(1.7),MooTools(2.0),Firebug(1.8)andeven
jQuery(1.7).AlthoughthetermCommonJSAMDformathasbeenseeninthewildon
occasion,it'sbesttorefertoitasjustAMDorAsyncModulesupportasnotallparticipants
ontheCJSlistwishedtopursueit.

Note:TherewasatimewhentheproposalwasreferredtoasModulesTransport/C,
howeverasthespecwasn'tgearedfortransportingexistingCJSmodules,butrather,for
deningmodulesitmademoresensetooptfortheAMDnamingconvention.

GettingStartedWithModules

https://addyosmani.com/writingmodularjs/ 3/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

Thetwokeyconceptsyouneedtobeawareofherearetheideaofa define methodfor


facilitatingmoduledenitionanda require methodforhandlingdependencyloading.
deneisusedtodenenamedorunnamedmodulesbasedontheproposalusingthe
followingsignature:

1.define(
2.module_id/*optional*/,
3.[dependencies]/*optional*/,
4.definitionfunction/*functionforinstantiatingthemoduleorobject*/
5.)

Asyoucantellbytheinlinecomments,the module_id isanoptionalargumentwhichis


typicallyonlyrequiredwhennonAMDconcatenationtoolsarebeingused(theremaybe
someotheredgecaseswhereit'susefultoo).Whenthisargumentisleftout,wecallthe
moduleanonymous.

Whenworkingwithanonymousmodules,theideaofamodule'sidentityisDRY,makingit
trivialtoavoidduplicationoflenamesandcode.Becausethecodeismoreportable,itcan
beeasilymovedtootherlocations(oraroundthelesystem)withoutneedingtoalterthe
codeitselforchangeitsID.The module_id isequivalenttofolderpathsinsimplepackages
andwhennotusedinpackages.Developerscanalsorunthesamecodeonmultiple
environmentsjustbyusinganAMDoptimizerthatworkswithaCommonJSenvironment
suchasr.js.

Backtothedenesignature,thedependenciesargumentrepresentsanarrayof
dependencieswhicharerequiredbythemoduleyouaredeningandthethirdargument
('denitionfunction')isafunctionthat'sexecutedtoinstantiateyourmodule.Abarebone
modulecouldbedenedasfollows:

UnderstandingAMD:dene()

1.
2.//Amodule_id(myModule)isusedherefordemonstrationpurposesonly
3.
4.define('myModule',
5.['foo','bar'],
https://addyosmani.com/writingmodularjs/ 4/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

6.//moduledefinitionfunction
7.//dependencies(fooandbar)aremappedtofunctionparameters
8.function(foo,bar){
9.//returnavaluethatdefinesthemoduleexport
10.//(i.ethefunctionalitywewanttoexposeforconsumption)
11.
12.//createyourmodulehere
13.varmyModule={
14.doStuff:function(){
15.console.log('Yay!Stuff')
16.}
17.}
18.
19.returnmyModule
20.})
21.
22.//Analternativeexamplecouldbe..
23.define('myModule',
24.['math','graph'],
25.function(math,graph){
26.
27.//Notethatthisisaslightlydifferentpattern
28.//WithAMD,it'spossibletodefinemodulesinafew
29.//differentwaysdueasit'srelativelyflexiblewith
30.//certainaspectsofthesyntax
31.return{
32.plot:function(x,y){
33.returngraph.drawPie(math.randomGrid(x,y))
34.}
35.}
36.}
37.})

requireontheotherhandistypicallyusedtoloadcodeinatoplevelJavaScriptleorwithin
amoduleshouldyouwishtodynamicallyfetchdependencies.Anexampleofitsusageis:

https://addyosmani.com/writingmodularjs/ 5/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

UnderstandingAMD:require()

1.//Consider'foo'and'bar'aretwoexternalmodules
2.//Inthisexample,the'exports'fromthetwomodulesloadedarepassedas
3.//functionargumentstothecallback(fooandbar)
4.//sothattheycansimilarlybeaccessed
5.
6.require(['foo','bar'],function(foo,bar){
7.//restofyourcodehere
8.foo.doSomething()
9.})

DynamicallyloadedDependencies

1.
2.define(function(require){
3.varisReady=false,foobar
4.
5.//notetheinlinerequirewithinourmoduledefinition
6.require(['foo','bar'],function(foo,bar){
7.isReady=true
8.foobar=foo()+bar()
9.})
10.
11.//wecanstillreturnamodule
12.return{
13.isReady:isReady,
14.foobar:foobar
15.}
16.})
17.

UnderstandingAMD:plugins
ThefollowingisanexampleofdeninganAMDcompatibleplugin:

https://addyosmani.com/writingmodularjs/ 6/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

1.//WithAMD,it'spossibletoloadinassetsofalmostanykind
2.//includingtextfilesandHTML.Thisenablesustohavetemplate
3.//dependencieswhichcanbeusedtoskincomponentseitheron
4.//pageloadordynamically.
5.
6.define(['./templates','text!./template.md','css!./template.css'],
7.function(templates,template){
8.console.log(templates)
9.//dosomefuntemplatestuffhere.
10.}
11.})

Note:Althoughcss!isincludedforloadingCSSdependenciesintheaboveexample,it's
importanttorememberthatthisapproachhassomecaveatssuchasitnotbeingfully
possibletoestablishwhentheCSSisfullyloaded.Dependingonhowyouapproach
yourbuild,itmayalsoresultinCSSbeingincludedasadependencyintheoptimized
le,souseCSSasaloadeddependencyinsuchcaseswithcaution.

LoadingAMDModulesUsingrequire.js

1.require(['app/myModule'],
2.function(myModule){
3.//startthemainmodulewhichinturn
4.//loadsothermodules
5.varmodule=newmyModule()
6.module.doStuff()
7.})

LoadingAMDModulesUsingcurl.js

1.curl(['app/myModule.js'],
2.function(myModule){
3.//startthemainmodulewhichinturn
4.//loadsothermodules
5.varmodule=newmyModule()
https://addyosmani.com/writingmodularjs/ 7/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

6.module.doStuff()
7.})

ModulesWithDeferredDependencies
1.//ThiscouldbecompatiblewithjQuery'sDeferredimplementation,
2.//futures.js(slightlydifferentsyntax)oranyoneofanumber
3.//ofotherimplementations
4.define(['lib/Deferred'],function(Deferred){
5.vardefer=newDeferred()
6.require(['lib/templates/?index.html','lib/data/?stats'],
7.function(template,data){
8.defer.resolve({template:template,data:data})
9.}
10.)
11.returndefer.promise()
12.})

WhyIsAMDABetterChoiceForWritingModularJavaScript?
Providesaclearproposalforhowtoapproachdeningexiblemodules.
Signicantlycleanerthanthepresentglobalnamespaceand <script> tagsolutions
manyofusrelyon.There'sacleanwaytodeclarestandalonemodulesand
dependenciestheymayhave.
Moduledenitionsareencapsulated,helpingustoavoidpollutionoftheglobal
namespace.
Worksbetterthansomealternativesolutions(eg.CommonJS,whichwe'llbelookingat
shortly).Doesn'thaveissueswithcrossdomain,localordebugginganddoesn'thavea
relianceonserversidetoolstobeused.MostAMDloaderssupportloadingmodulesin
thebrowserwithoutabuildprocess.
Providesa'transport'approachforincludingmultiplemodulesinasinglele.Other
approacheslikeCommonJShaveyettoagreeonatransportformat.

https://addyosmani.com/writingmodularjs/ 8/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

It'spossibletolazyloadscriptsifthisisneeded.

RelatedReading
TheRequireJSGuideToAMD
What'sthefastestwaytoloadAMDmodules?
AMDvs.CJS,what'sthebetterformat?
AMDIsBetterForTheWebThanCommonJSModules
TheFutureIsModulesNotFrameworks
AMDNoLongerACommonJSSpecication
OnInventingJavaScriptModuleFormatsAndScriptLoaders
TheAMDMailingList

AMDModulesWithDojo
DeningAMDcompatiblemodulesusingDojoisfairlystraightforward.Asperabove,
deneanymoduledependenciesinanarrayastherstargumentandprovideacallback
(factory)whichwillexecutethemoduleoncethedependencieshavebeenloaded.e.g:

1.define(["dijit/Tooltip"],function(Tooltip){
2.//Ourdijittooltipisnowavailableforlocaluse
3.newTooltip(...)
4.})

NotetheanonymousnatureofthemodulewhichcannowbebothconsumedbyaDojo
asynchronousloader,RequireJSorthestandarddojo.require()moduleloaderthatyoumay
beusedtousing.

Forthosewonderingaboutmodulereferencing,therearesomeinterestinggotchasthatare
usefultoknowhere.AlthoughtheAMDadvocatedwayofreferencingmodulesdeclares

https://addyosmani.com/writingmodularjs/ 9/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

theminthedependencylistwithasetofmatchingarguments,thisisn'tsupportedbythe
Dojo1.6buildsystemitreallyonlyworksforAMDcompliantloaders.e.g:

1.define(["dojo/cookie","dijit/Tooltip"],function(cookie,Tooltip){
2.varcookieValue=cookie("cookieName")
3.newTree(...)
4.})

Thishasmanyadvancesovernestednamespacingasmodulesnolongerneedtodirectly
referencecompletenamespaceseverytimeallwerequireisthe'dojo/cookie'pathin
dependencies,whichoncealiasedtoanargument,canbereferencedbythatvariable.This
removestheneedtorepeatedlytypeout'dojo.'inyourapplications.

Note:AlthoughDojo1.6doesn'tociallysupportuserbasedAMDmodules(nor
asynchronousloading),it'spossibletogetthisworkingwithDojousinganumberof
dierentscriptloaders.Atpresent,allDojocoreandDijitmoduleshavebeen
transformedtotheAMDsyntaxandimprovedoverallAMDsupportwilllikelyland
between1.7and2.0.

ThenalgotchatobeawareofisthatifyouwishtocontinueusingtheDojobuildsystemor
wishtomigrateoldermodulestothisnewerAMDstyle,thefollowingmoreverboseversion
enableseasiermigration.Noticethatdojoanddijitandreferencedasdependenciestoo:

1.define(["dojo","dijit","dojo/cookie","dijit/Tooltip"],function(dojo,
dijit){
2.varcookieValue=dojo.cookie("cookieName")
3.newdijit.Tooltip(...)
4.})

AMDModuleDesignPatterns(Dojo)

https://addyosmani.com/writingmodularjs/ 10/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

Ifyou'vefollowedanyofmypreviouspostsonthebenetsofdesignpatterns,you'llknow
thattheycanbehighlyeectiveinimprovinghowweapproachstructuringsolutionsto
commondevelopmentproblems.JohnHannrecentlygaveanexcellentpresentationabout
AMDmoduledesignpatternscoveringtheSingleton,Decorator,Mediatorandothers.I
highlyrecommendcheckingouthisslidesifyougetachance.

Somesamplesofthesepatternscanbefoundbelow:
Decoratorpattern:

1.
2.//mylib/UpdatableObservable:adecoratorfordojo/store/Observable
3.define(['dojo','dojo/store/Observable'],function(dojo,Observable){
4.returnfunctionUpdatableObservable(store){
5.
6.varobservable=dojo.isFunction(store.notify)?store:
7.newObservable(store)
8.
9.observable.updated=function(object){
10.dojo.when(object,function(itemOrArray){
11.dojo.forEach([].concat(itemOrArray),this.notify,this)
12.}
13.}
14.
15.returnobservable//makes`new`optional
16.}
17.})
18.
19.
20.//decoratorconsumer
21.//aconsumerformylib/UpdatableObservable
22.
23.define(['mylib/UpdatableObservable'],function(makeUpdatable){
24.varobservable,updatable,someItem
25.//...herebecodetogetorcreate`observable`
26.
27.//...maketheobservablestoreupdatable

https://addyosmani.com/writingmodularjs/ 11/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

28.updatable=makeUpdatable(observable)//`new`isoptional!
29.
30.//...later,whenacometdmessagearriveswithnewdataitem
31.updatable.updated(updatedItem)
32.})
33.

Adapterpattern

1.
2.//'mylib/Array'adapts`each`functiontomimicjQuery's:
3.define(['dojo/_base/lang','dojo/_base/array'],function(lang,array){
4.returnlang.delegate(array,{
5.each:function(arr,lambda){
6.array.forEach(arr,function(item,i){
7.lambda.call(item,i,item)//likejQuery'seach
8.})
9.}
10.})
11.})
12.
13.//adapterconsumer
14.//'myapp/mymodule':
15.define(['mylib/Array'],function(array){
16.array.each(['uno','dos','tres'],function(i,esp){
17.//here,`this`==item
18.})
19.})
20.

AMDModulesWithjQuery

https://addyosmani.com/writingmodularjs/ 12/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

TheBasics
UnlikeDojo,jQueryreallyonlycomeswithonele,howevergiventhepluginbasednature
ofthelibrary,wecandemonstratehowstraightforwarditistodeneanAMDmodulethat
usesitbelow.

1.define(['js/jquery.js','js/jquery.color.js','js/underscore.js'],
2.function($,colorPlugin,_){
3.//Herewe'vepassedinjQuery,thecolorpluginandUnderscore
4.//Noneofthesewillbeaccessibleintheglobalscope,butwe
5.//caneasilyreferencethembelow.
6.
7.//Pseudorandomizeanarrayofcolors,selectingthefirst
8.//itemintheshuffledarray
9.varshuffleColor=_.first(_.shuffle(['#666','#333','#111']))
10.
11.//Animatethebackgroundcolorofanyelementswiththeclass
12.//'item'onthepageusingtheshuffledcolor
13.$('.item').animate({'backgroundColor':shuffleColor})
14.
15.return{}
16.//Whatwereturncanbeusedbyothermodules
17.})

Thereishoweversomethingmissingfromthisexampleandit'stheconceptofregistration.

RegisteringjQueryAsAnAsynccompatibleModule
OneofthekeyfeaturesthatlandedinjQuery1.7wassupportforregisteringjQueryasan
asynchronousmodule.Thereareanumberofcompatiblescriptloaders(including
RequireJSandcurl)whicharecapableofloadingmodulesusinganasynchronousmodule
formatandthismeansfewerhacksarerequiredtogetthingsworking.

AsaresultofjQuery'spopularity,AMDloadersneedtotakeintoaccountmultipleversions
ofthelibrarybeingloadedintothesamepageasyouideallydon'twantseveraldierent
versionsloadingatthesametime.Loadershavetheoptionofeitherspecicallytakingthis

https://addyosmani.com/writingmodularjs/ 13/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

issueintoaccountorinstructingtheirusersthatthereareknownissueswiththirdparty
scriptsandtheirlibraries.

Whatthe1.7additionbringstothetableisthatithelpsavoidissueswithotherthirdparty
codeonapageaccidentallyloadingupaversionofjQueryonthepagethattheowner
wasn'texpecting.Youdon'twantotherinstancesclobberingyourownandsothiscanbeof
benet.

Thewaythisworksisthatthescriptloaderbeingemployedindicatesthatitsupports
multiplejQueryversionsbyspecifyingthataproperty, define.amd.jQuery isequaltotrue.
Forthoseinterestedinmorespecicimplementationdetails,weregisterjQueryasanamed
moduleasthereisariskthatitcanbeconcatenatedwithotherleswhichmayuseAMD's
define() method,butnotuseaproperconcatenationscriptthatunderstandsanonymous
AMDmoduledenitions.

ThenamedAMDprovidesasafetyblanketofbeingbothrobustandsafeformostusecases.

//Accountfortheexistenceofmorethanoneglobal
//instancesofjQueryinthedocument,caterfortesting
//.noConflict()

varjQuery=this.jQuery||"jQuery",
$=this.$||"$",
originaljQuery=jQuery,
original$=$,
amdDefined

define(['jquery'],function($){
$('.items').css('background','green')
returnfunction(){}
})

//Theveryeasytoimplementflagstatingsupportwhich
//wouldbeusedbytheAMDloader
define.amd={
jQuery:true
}

https://addyosmani.com/writingmodularjs/ 14/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

SmarterjQueryPlugins
I'verecentlydiscussedsomeideasandexamplesofhowjQuerypluginscouldbewritten
usingUniversalModuleDenition(UMD)patternshere.UMDsdenemodulesthatcan
workonboththeclientandserver,aswellaswithallpopularscriptloadersavailableatthe
moment.Whilstthisisstillanewareawithalotofconceptsstillbeingnalized,feelfreeto
lookatthecodesamplesinthesectiontitleAMD&&CommonJSbelowandletmeknowif
youfeelthere'sanythingwecoulddobetter.

WhatScriptLoaders&FrameworksSupportAMD?
Inbrowser:
RequireJShttp://requirejs.org
curl.jshttp://github.com/unscriptable/curl
bdLoadhttp://bdframework.com/bdLoad
Yabblehttp://github.com/jbrantly/yabble
PINFhttp://github.com/pinf/loaderjs
(andmore)

Serverside:
RequireJShttp://requirejs.org
PINFhttp://github.com/pinf/loaderjs

AMDConclusions
TheaboveareverytrivialexamplesofjusthowusefulAMDmodulescantrulybe,butthey
hopefullyprovideafoundationforunderstandinghowtheywork.

Youmaybeinterestedtoknowthatmanyvisiblelargeapplicationsandcompaniescurrently
useAMDmodulesasapartoftheirarchitecture.TheseincludeIBMandtheBBCiPlayer,
whichhighlightjusthowseriouslythisformatisbeingconsideredbydevelopersatan
enterpriselevel.

https://addyosmani.com/writingmodularjs/ 15/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

FormorereasonswhymanydevelopersareoptingtouseAMDmodulesintheir
applications,youmaybeinterestedinthispostbyJamesBurke.

CommonJSAModuleFormatOptimizedForTheServer
CommonJSareavolunteerworkinggroupwhichaimtodesign,prototypeandstandardize
JavaScriptAPIs.Todatethey'veattemptedtoratifystandardsforbothmodulesand
packages.TheCommonJSmoduleproposalspeciesasimpleAPIfordeclaringmodules
serversideandunlikeAMDattemptstocoverabroadersetofconcernssuchasio,
lesystem,promisesandmore.

GettingStarted
Fromastructureperspective,aCJSmoduleisareusablepieceofJavaScriptwhichexports
specicobjectsmadeavailabletoanydependentcodetherearetypicallynofunction
wrappersaroundsuchmodules(soyouwon'tsee define usedhereforexample).

Atahighleveltheybasicallycontaintwoprimaryparts:afreevariablenamed exports
whichcontainstheobjectsamodulewishestomakeavailabletoothermodulesanda
require functionthatmodulescanusetoimporttheexportsofothermodules.

UnderstandingCJS:require()andexports

1.//package/libisadependencywerequire
2.varlib=require('package/lib')
3.
4.//somebehaviourforourmodule
5.functionfoo(){
6.lib.log('helloworld!')
7.}
8.
9.//export(expose)footoothermodules
10.exports.foo=foo

https://addyosmani.com/writingmodularjs/ 16/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

Basicconsumptionofexports

1.
2.//definemorebehaviourwewouldliketoexpose
3.functionfoobar(){
4.this.foo=function(){
5.console.log('Hellofoo')
6.}
7.
8.this.bar=function(){
9.console.log('Hellobar')
10.}
11.}
12.
13.//exposefoobartoothermodules
14.exports.foobar=foobar
15.
16.
17.//anapplicationconsuming'foobar'
18.
19.//accessthemodulerelativetothepath
20.//wherebothusageandmodulefilesexist
21.//inthesamedirectory
22.
23.varfoobar=require('./foobar').foobar,
24.test=newfoobar()
25.
26.test.bar()//'Hellobar'
27.

AMDequivalentOfTheFirstCJSExample

1.define(['package/lib'],function(lib){
2.
3.//somebehaviourforourmodule

https://addyosmani.com/writingmodularjs/ 17/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

4.functionfoo(){
5.lib.log('helloworld!')
6.}
7.
8.//export(expose)fooforothermodules
9.return{
10.foobar:foo
11.}
12.})

ConsumingMultipleDependencies
app.js

1.varmodA=require('./foo')
2.varmodB=require('./bar')
3.
4.exports.app=function(){
5.console.log('Imanapplication!')
6.}
7.
8.exports.foo=function(){
9.returnmodA.helloWorld()
10.}

bar.js

1.exports.name='bar'

foo.js

1.require('./bar')
2.exports.helloWorld=function(){
3.return'HelloWorld!!''
4.}
https://addyosmani.com/writingmodularjs/ 18/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

WhatLoaders&FrameworksSupportCJS?
Inbrowser:
curl.jshttp://github.com/unscriptable/curl
SproutCore1.1http://sproutcore.com
PINFhttp://github.com/pinf/loaderjs
(andmore)

Serverside:
Nodehttp://nodejs.org
Narwhalhttps://github.com/tlrobinson/narwhal
Perseverehttp://www.persvr.org/
Wakandahttp://www.wakandasoft.com/

IsCJSSuitableForTheBrowser?
TherearedevelopersthatfeelCommonJSisbettersuitedtoserversidedevelopmentwhich
isonereasonthere'scurrentlyalevelofdisagreementoverwhichformatshouldandwill
beusedasthedefactostandardinthepreHarmonyagemovingforward.Someofthe
argumentsagainstCJSincludeanotethatmanyCommonJSAPIsaddressserveroriented
featureswhichonewouldsimplynotbeabletoimplementatabrowserlevelinJavaScript
forexample,io,systemandjscouldbeconsideredunimplementablebythenatureoftheir
functionality.

Thatsaid,it'susefultoknowhowtostructureCJSmodulesregardlesssothatwecanbetter
appreciatehowtheytinwhendeningmoduleswhichmaybeusedeverywhere.Modules
whichhaveapplicationsonboththeclientandserverincludevalidation,conversionand
templatingengines.Thewaysomedevelopersareapproachingchoosingwhichformatto
useisoptingforCJSwhenamodulecanbeusedinaserversideenvironmentandusing
AMDifthisisnotthecase.

https://addyosmani.com/writingmodularjs/ 19/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

AsAMDmodulesarecapableofusingpluginsandcandenemoregranularthingslike
constructorsandfunctionsthismakessense.CJSmodulesareonlyabletodeneobjects
whichcanbetedioustoworkwithifyou'retryingtoobtainconstructorsoutofthem.

Althoughit'sbeyondthescopeofthisarticle,youmayhavealsonoticedthattherewere
dierenttypesof'require'methodsmentionedwhendiscussingAMDandCJS.

Theconcernwithasimilarnamingconventionisofcourseconfusionandthecommunity
arecurrentlysplitonthemeritsofaglobalrequirefunction.JohnHann'ssuggestionhereis
thatratherthancallingit'require',whichwouldprobablyfailtoachievethegoalof
informingusersaboutthedierentbetweenaglobalandinnerrequire,itmaymakemore
sensetorenamethegloballoadermethodsomethingelse(e.g.thenameofthelibrary).It's
forthisreasonthataloaderlikecurl.jsuses curl() asopposedto require .

RelatedReading
DemystifyingCommonJSModules
JavaScriptGrowingUp
TheRequireJSNotesOnCommonJS
TakingBabyStepsWithNode.jsAndCommonJSCreatingCustomModules
AsynchronousCommonJSModulesfortheBrowser
TheCommonJSMailingList

AMD&&CommonJSCompeting,ButEquallyValidStandards
WhilstthisarticlehasplacedmoreemphasisonusingAMDoverCJS,therealityisthatboth
formatsarevalidandhaveause.

AMDadoptsabrowserrstapproachtodevelopment,optingforasynchronousbehaviour
andsimpliedbackwardscompatabilitybutitdoesn'thaveanyconceptofFileI/O.It
supportsobjects,functions,constructors,strings,JSONandmanyothertypesofmodules,
runningnativelyinthebrowser.It'sincrediblyexible.
https://addyosmani.com/writingmodularjs/ 20/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

CommonJSontheotherhandtakesaserverrstapproach,assumingsynchronous
behaviour,noglobalbaggageasJohnHannwouldrefertoitasanditattemptstocaterfor
thefuture(ontheserver).WhatwemeanbythisisthatbecauseCJSsupportsunwrapped
modules,itcanfeelalittlemoreclosetotheES.next/Harmonyspecications,freeingyouof
the define() wrapperthatAMDenforces.CJSmoduleshoweveronlysupportobjectsas
modules.

Althoughtheideaofyetanothermoduleformatmaybedaunting,youmaybeinterestedin
somesamplesofworkonhybridAMD/CJSandUniveralAMD/CJSmodules.

BasicAMDHybridFormat(JohnHann)

1.define(function(require,exports,module){
2.
3.varshuffler=require('lib/shuffle')
4.
5.exports.randomize=function(input){
6.returnshuffler.shuffle(input)
7.}
8.})

AMD/CommonJSUniversalModuleDenition(Variation2,UMDjs)

1./**
2.*exportsobjectbasedversion,ifyouneedtomakea
3.*circulardependencyorneedcompatibilitywith
4.*commonjslikeenvironmentsthatarenotNode.
5.*/
6.(function(define){
7.//The'id'isoptional,butrecommendedifthisis
8.//apopularweblibrarythatisusedmostlyin
9.//nonAMD/Nodeenvironments.However,ifwant
10.//tomakeananonymousmodule,removethe'id'
11.//below,andremovetheiduseinthedefineshim.
12.define('id',function(require,exports){
13.//Ifhavedependencies,getthemhere

https://addyosmani.com/writingmodularjs/ 21/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

14.vara=require('a')
15.
16.//Attachpropertiestoexports.
17.exports.name=value
18.})
19.}(typeofdefine==='function'&&define.amd?define:function(id,
factory){
20.if(typeofexports!=='undefined'){
21.//commonjs
22.factory(require,exports)
23.}else{
24.//Createaglobalfunction.Onlyworksif
25.//thecodedoesnothavedependencies,or
26.//dependenciesfitthecallpatternbelow.
27.factory(function(value){
28.returnwindow[value]
29.},(window[id]={}))
30.}
31.}))

ExtensibleUMDPluginsWith(VariationbymyselfandThomas
Davis).
core.js

1.//Module/Plugincore
2.//Note:thewrappercodeyouseearoundthemoduleiswhatenables
3.//ustosupportmultiplemoduleformatsandspecificationsby
4.//mappingtheargumentsdefinedtowhataspecificformatexpects
5.//tobepresent.Ouractualmodulefunctionalityisdefinedlower
6.//down,whereanamedmoduleandexportsaredemonstrated.
7.
8.(function(name,definition){
9.vartheModule=definition(),
10.//thisisconsidered"safe":

https://addyosmani.com/writingmodularjs/ 22/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

11.hasDefine=typeofdefine==='function'&&define.amd,
12.//hasDefine=typeofdefine==='function',
13.hasExports=typeofmodule!=='undefined'&&module.exports
14.
15.if(hasDefine){//AMDModule
16.define(theModule)
17.}elseif(hasExports){//Node.jsModule
18.module.exports=theModule
19.}else{//Assigntocommonnamespacesorsimplytheglobalobject
(window)
20.(this.jQuery||this.ender||this.$||this)[name]=theModule
21.}
22.})('core',function(){
23.varmodule=this
24.module.plugins=[]
25.module.highlightColor="yellow"
26.module.errorColor="red"
27.
28.//definethecoremodulehereandreturnthepublicAPI
29.
30.//thisisthehighlightmethodusedbythecorehighlightAll()
31.//methodandallofthepluginshighlightingelementsdifferent
32.//colors
33.module.highlight=function(el,strColor){
34.//thismoduleusesjQuery,howeverplainoldJavaScript
35.//orsay,Dojocouldbejustaseasilyused.
36.if(this.jQuery){
37.jQuery(el).css('background',strColor)
38.}
39.}
40.return{
41.highlightAll:function(){
42.module.highlight('div',module.highlightColor)
43.}
44.}
45.

https://addyosmani.com/writingmodularjs/ 23/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

46.})

myExtension.js

1.(function(name,definition){
2.vartheModule=definition(),
3.hasDefine=typeofdefine==='function',
4.hasExports=typeofmodule!=='undefined'&&module.exports
5.
6.if(hasDefine){//AMDModule
7.define(theModule)
8.}elseif(hasExports){//Node.jsModule
9.module.exports=theModule
10.}else{//Assigntocommonnamespacesorsimplytheglobalobject
(window)
11.
12.
13.//accountforforflatfile/globalmoduleextensions
14.varobj=null
15.varnamespaces=name.split(".")
16.varscope=(this.jQuery||this.ender||this.$||this)
17.for(vari=0i<namespaces.lengthi++){
18.varpackageName=namespaces[i]
19.if(obj&&i==namespaces.length1){
20.obj[packageName]=theModule
21.}elseif(typeofscope[packageName]==="undefined"){
22.scope[packageName]={}
23.}
24.obj=scope[packageName]
25.}
26.
27.}
28.})('core.plugin',function(){
29.
30.//defineyourmodulehereandreturnthepublicAPI
31.//thiscodecouldbeeasilyadaptedwiththecoreto

https://addyosmani.com/writingmodularjs/ 24/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

32.//allowformethodsthatoverwrite/extendcorefunctionality
33.//toexpandthehighlightmethodtodomoreifyouwished.
34.return{
35.setGreen:function(el){
36.highlight(el,'green')
37.},
38.setRed:function(el){
39.highlight(el,errorColor)
40.}
41.}
42.
43.})

app.js

1.$(function(){
2.
3.//theplugin'core'isexposedunderacorenamespacein
4.//thisexamplewhichwefirstcache
5.varcore=$.core
6.
7.//usethenusesomeofthebuiltincorefunctionalityto
8.//highlightalldivsinthepageyellow
9.core.highlightAll()
10.
11.//accesstheplugins(extensions)loadedintothe'plugin'
12.//namespaceofourcoremodule:
13.
14.//Setthefirstdivinthepagetohaveagreenbackground.
15.core.plugin.setGreen("div:first")
16.//Herewe'remakinguseofthecore's'highlight'method
17.//underthehoodfromapluginloadedinafterit
18.
19.//Setthelastdivtothe'errorColor'propertydefinedin
20.//ourcoremodule/plugin.Ifyoureviewthecodefurtherdown
21.//you'llseehoweasyitistoconsumepropertiesandmethods

https://addyosmani.com/writingmodularjs/ 25/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

22.//betweenthecoreandotherplugins
23.core.plugin.setRed('div:last')
24.})

ESHarmonyModulesOfTheFuture
TC39,thestandardsbodychargedwithdeningthesyntaxandsemanticsofECMAScript
anditsfutureiterationsiscomposedofanumberofveryintelligentdevelopers.Someof
thesedevelopers(suchasAlexRussell)havebeenkeepingacloseeyeontheevolutionof
JavaScriptusageforlargescaledevelopmentoverthepastfewyearsandareacutelyawareof
theneedforbetterlanguagefeaturesforwritingmoremodularJS.

Forthisreason,therearecurrentlyproposalsforanumberofexcitingadditionstothe
languageincludingexiblemodulesthatcanworkonboththeclientandserver,amodule
loaderandmore.Inthissection,I'llbeshowingyousomecodesamplesofthesyntaxfor
modulesinES.nextsoyoucangetatasteofwhat'stocome.

Note:AlthoughHarmonyisstillintheproposalphases,youcanalreadytryout
(partial)featuresofES.nextthataddressnativesupportforwritingmodularJavaScript
thankstoGoogle'sTraceurcompiler.TogetupandrunningwithTraceurinundera
minute,readthisgettingstartedguide.There'salsoaJSConfpresentationaboutit
that'sworthlookingatifyou'reinterestedinlearningmoreabouttheproject.

ModulesWithImportsAndExports
Ifyou'vereadthroughthesectionsonAMDandCJSmodulesyoumaybefamiliarwiththe
conceptofmoduledependencies(imports)andmoduleexports(or,thepublicAPI/variables
weallowothermodulestoconsume).InES.next,theseconceptshavebeenproposedina
slightlymoresuccinctmannerwithdependenciesbeingspeciedusingan import keyword.
export isn'tgreatlydierenttowhatwemightexpectandIthinkmanydeveloperswilllook
atthecodebelowandinstantly'get'it.

https://addyosmani.com/writingmodularjs/ 26/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

importdeclarationsbindamodule'sexportsaslocalvariablesandmayberenamedto
avoidnamecollisions/conicts.
exportdeclarationsdeclarethatalocalbindingofamoduleisexternallyvisiblesuch
thatothermodulesmayreadtheexportsbutcan'tmodifythem.Interestingly,modules
mayexportchildmoduleshowevercan'texportmodulesthathavebeendened
elsewhere.Youmayalsorenameexportssotheirexternalnamediersfromtheirlocal
names.

1.
2.modulestaff{
3.//specify(public)exportsthatcanbeconsumedby
4.//othermodules
5.exportvarbaker={
6.bake:function(item){
7.console.log('Woo!Ijustbaked'+item)
8.}
9.}
10.}
11.
12.moduleskills{
13.exportvarspecialty="baking"
14.exportvarexperience="5years"
15.}
16.
17.modulecakeFactory{
18.
19.//specifydependencies
20.importbakerfromstaff
21.
22.//importeverythingwithwildcards
23.import*fromskills
24.
25.exportvaroven={
26.makeCupcake:function(toppings){

https://addyosmani.com/writingmodularjs/ 27/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

27.baker.bake('cupcake',toppings)
28.},
29.makeMuffin:function(mSize){
30.baker.bake('muffin',size)
31.}
32.}
33.}

ModulesLoadedFromRemoteSources
Themoduleproposalsalsocaterformoduleswhichareremotelybased(e.g.athirdparty
APIwrapper)makingitsimplistictoloadmodulesinfromexternallocations.Here'san
exampleofuspullinginthemodulewedenedaboveandutilizingit:

1.modulecakeFactoryfrom'http://addyosmani.com/factory/cakes.js'
2.cakeFactory.oven.makeCupcake('sprinkles')
3.cakeFactory.oven.makeMuffin('large')

ModuleLoaderAPI
ThemoduleloaderproposeddescribesadynamicAPIforloadingmodulesinhighly
controlledcontexts.Signaturessupportedontheloaderinclude load(url,
moduleInstance,error) forloadingmodules, createModule(object,
globalModuleReferences) andothers.Here'sanotherexampleofusdynamicallyloadingin
themoduleweinitiallydened.Notethatunlikethelastexamplewherewepulledina
modulefromaremotesource,themoduleloaderAPIisbettersuitedtodynamiccontexts.

1.Loader.load('http://addyosmani.com/factory/cakes.js',
2.function(cakeFactory){
3.cakeFactory.oven.makeCupcake('chocolate')
4.})

CommonJSlikeModulesForTheServer

https://addyosmani.com/writingmodularjs/ 28/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

Fordeveloperswhoareserveroriented,themodulesystemproposedforES.nextisn'tjust
constrainedtolookingatmodulesinthebrowser.Belowforexamples,youcanseeaCJSlike
moduleproposedforuseontheserver:

1.//io/File.js
2.exportfunctionopen(path){...}
3.exportfunctionclose(hnd){...}

1.//compiler/LexicalHandler.js
2.modulefilefrom'io/File'
3.
4.import{open,close}fromfile
5.exportfunctionscan(in){
6.try{
7.varh=open(in)...
8.}
9.finally{close(h)}
10.}

1.modulelexerfrom'compiler/LexicalHandler'
2.modulestdlibfrom'@std'
3.
4.//...scan(cmdline[0])...

ClassesWithConstructors,Getters&Setters
Thenotionofaclasshasalwaysbeenacontentiousissuewithpuristsandwe'vesofargot
alongwitheitherfallingbackonJavaScript'sprototypalnatureorthroughusingframeworks
orabstractionsthatoertheabilitytouseclassdenitionsinaformthatdesugarstothe
sameprototypalbehavior.

InHarmony,classescomeaspartofthelanguagealongwithconstructorsand(nally)some
senseoftrueprivacy.Inthefollowingexamples,I'veincludedsomeinlinecommentstohelp
youunderstandhowclassesarestructured,butyoumayalsonoticethelackoftheword

https://addyosmani.com/writingmodularjs/ 29/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

'function'inhere.Thisisn'tatypoerror:TC39havebeenmakingaconsciouseortto
decreaseourabuseofthe function keywordforeverythingandthehopeisthatthiswill
helpsimplifyhowwewritecode.

1.classCake{
2.
3.//Wecandefinethebodyofaclass'constructor
4.//functionbyusingthekeyword'constructor'followed
5.//byanargumentlistofpublicandprivatedeclarations.
6.constructor(name,toppings,price,cakeSize){
7.publicname=name
8.publiccakeSize=cakeSize
9.publictoppings=toppings
10.privateprice=price
11.
12.}
13.
14.//AsapartofES.next'seffortstodecreasetheunnecessary
15.//useof'function'foreverything,you'llnoticethatit's
16.//droppedforcasessuchasthefollowing.Hereanidentifier
17.//followedbyanargumentlistandabodydefinesanewmethod
18.
19.addTopping(topping){
20.public(this).toppings.push(topping)
21.}
22.
23.//Getterscanbedefinedbydeclaringgetbefore
24.//anidentifier/methodnameandacurlybody.
25.getallToppings(){
26.returnpublic(this).toppings
27.}
28.
29.getqualifiesForDiscount(){
30.returnprivate(this).price>5
31.}
32.

https://addyosmani.com/writingmodularjs/ 30/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

33.//Similartogetters,setterscanbedefinedbyusing
34.//the'set'keywordbeforeanidentifier
35.setcakeSize(cSize){
36.if(cSize<0){
37.thrownewError('Cakemustbeavalidsize
38.eithersmall,mediumorlarge')
39.}
40.public(this).cakeSize=cSize
41.}
42.
43.
44.}

ESHarmonyConclusions
Asyoucansee,ES.nextiscomingwithsomeexcitingnewadditions.AlthoughTraceurcan
beusedtoanextenttotryoursuchfeaturesinthepresent,rememberthatitmaynotbethe
bestideatoplanoutyoursystemtouseHarmony(justyet).Therearerisksheresuchas
specicationschangingandapotentialfailureatthecrossbrowserlevel(IE9forexample
willtakeawhiletodie)soyourbestbetsuntilwehavebothspecnalizationandcoverage
areAMD(forinbrowsermodules)andCJS(forthoseontheserver).

RelatedReading
AFirstLookAtTheUpcomingJavaScriptModules
DavidHermanOnJavaScript/ES.Next(Video)
ESHarmonyModuleProposals
ESHarmonyModuleSemantics/StructureRationale
ESHarmonyClassProposals

ConclusionsAndFurtherReadingAReview
https://addyosmani.com/writingmodularjs/ 31/32
6/16/2017 WritingModularJavaScriptWithAMD,CommonJS&ESHarmony

Inthisarticlewe'vereviewedseveraloftheoptionsavailableforwritingmodularJavaScript
usingmodernmoduleformats.Theseformatshaveanumberofadvantagesoverusingthe
(classical)modulepatternaloneincluding:avoidinganeedfordeveloperstocreateglobal
variablesforeachmoduletheycreate,bettersupportforstaticanddynamicdependency
management,improvedcompatibilitywithscriptloaders,better(optional)compatibilityfor
modulesontheserverandmore.

Inshort,Irecommendtryingoutwhat'sbeensuggestedtodayastheseformatsoeralotof
powerandexibilitythatcanhelpwhenbuildingapplicationsbasedonmanyreusable
blocksoffunctionality.

Andthat'sitfornow.Ifyouhavefurtherquestionsaboutanyofthetopicscoveredtoday,
feelfreetohitmeupontwitterandI'lldomybesttohelp!

CopyrightAddyOsmani,2012.AllRightsReserved.

https://addyosmani.com/writingmodularjs/ 32/32

Você também pode gostar