|
HandsOn
Hands on DominoesDominoes as a simple script loaderAt its core, Dominoes is a javascript file loader. For instance, if you wish to execute some code that is dependant on the very popular jQuery framework, you would write something like this: dominoes( "http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" , function() {
// Your jQuery dependant code goes here
} );One thing that Dominoes ensures is that the same script won't be loaded twice so, if you have the following code later on: dominoes( "http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" , function() {
// Some other code also dependant on jQuery
} );The function will get executed right away since jQuery has already been loaded. Dominoes also detects when a request is made for a script that's already being loaded. So the two lines of codes above could be following one another and this wouldn't cause any trouble (and jQuery would still be loaded only once). Another thing Dominoes can do for you is when you need to load a script regularly because it's updating some DOM elements. By default, Dominoes would load it once and never do it again, but you can use the following syntax to get around the caching mechanism: dominoes( {
url: "http://mySite.org/js/updateUserTable.js",
cache: false
} , function() {
// Some code here, eventually
} );Dominoes as a stylesheet loaderDominoes can also load css stylesheets and will ensure the stylesheet has been properly loaded and applied before executing more code: dominoes( "$css(http://mysite/path/stylesheet.css)" , function() {
// The stylesheet has been loaded and applied
} );Like for scripts, Dominoes detects when a request is made for a stylesheet that's already being loaded. Dominoes as a substitution engineWriting urls can be cumbersome and Dominoes can help you there. Say most of your javascript scripts reside within "/u/kio/67/long/is/long/js/". Talk about typos in perspective. With Dominoes, you could do something like this: dominoes.property( "mySiteJSPath" , "http://mySite.org/u/kio/67/long/is/long/js" ); Then use this new-born property as follows: dominoes( "$(mySiteJSPath)/script1.js" , function1 ); dominoes( "$(mySiteJSPath)/script2.js" , function2 ); The substitution engine is even recursive, so it would be quite easy to handle subdirectories: dominoes.property( "mySiteGeolocPath" , "$(mySiteJSPath)/geoloc" ); dominoes.property( "mySiteAjaxPath" , "$(mySiteJSPath)/ajax" ); dominoes( "$(mySiteGeolocPath)/map.js" , geolocRelatedCode ); dominoes( "$(mySiteAjaxPath)/requests.js" , ajaxRelatedCode ); Dominoes as a dependency engineTake the following example: dominoes( "$(jQueryURL)", "./js/myScript/js", myFunction ); The problem here is that myScript will only get loaded once jQuery has been received entirely. This is quite inneficient if and when myScript does not use anything in jQuery. Thankfully, you can write the following: dominoes( "$(jQueryURL) ./js/myScript/js" , myFunction ); What the code above means is: "load jQuery & myScript in any order you like, then call myFunction". Dependency rulesIn fact, Dominoes provides a crude syntax to describe dependency rules:
Let's take a big, daunting, example to make things clear (hopefully): ( action1 > action2 ) action3 > (( action4 > action5 )) action6 >| action7 What we're expressing here is this: action2 depends on action1. Once action3 & action2 are done, we can get to the next group: here action4 & action6 can start. Since the "action4 > action5" rule is optional, action7 will be performed as soon as action6 is finished (provided the DOM is ready for manipulation). Still here? Because you may wonder what is meant by actions here. So here is an example with a syntax we haven't talked about yet: dominoes( {
chain: "$(JSON) $(jQuery) $(swfObject) > initCode >| domManipulation",
initCode: function() {
// Some library initialization code here
},
domManipulation: function() {
// DOM manipulation here
}
} );As you can see, once you define your rule as the chain attribute of an object litteral, the expression is parsed in the context of this litteral, thus making the initCode and domManipulation methods available. Rules repositoryLet's add some difficulty: first, let's say we want to run some code once jQuery is loaded. If we do: $(JSON) $(jQuery) > jQueryInitCode $(swfObject) > initCode >| domManipulation swfObject won't be loaded before jQuery and its init code are done. So we must use a sub-rule: $(JSON) ( $(jQuery) > jQueryInitCode ) $(swfObject) > initCode >| domManipulation But this makes the expression quite long now. Thankfully, we can write it like this: dominoes( {
chain: "$(JSON) jQuery $(swfObject) > initCode >| domManipulation",
jQuery: "$(jQuery) > jQueryInitCode",
jQueryInitCode: function() {
// jQuery specific init code goes here
},
initCode: function() {
// Library initialization code here
},
domManipulation: function() {
// DOM manipulation here
}
} );or even: dominoes( {
chain: "$(JSON) jQuery $(swfObject) > initCode >| domManipulation",
jQuery: {
chain: "$(jQuery) > initCode",
initCode: function() {
// jQuery specific init code goes here
}
},
initCode: function() {
// Library initialization code here
},
domManipulation: function() {
// DOM manipulation here
}
} );Now that could be a lot to write, especially if you have a lot of code depending on jQuery. However, Dominoes offers a repository for rules, so you could do something like this: dominoes.rule( "jQuery" , "$(jQuery)" , function() {
// jQuery specific init code goes here
} );
dominoes.rule( "JSLibs", "$(JSON) jQuery $(swfObject)" , function() {
// Library initialization code here
} ) ;
// And later on...
dominoes( "JSLibs >|" , function() {
// DOM manipulation here
} );Note how we dropped the object litterals syntax for a more straightforward arguments list. Note also that the function in the jQuery rule will only be ran once. This is a big advantage of defining named rules: they act like urls and are a one-time only occurence. Further DominoesThat's it for this hands on. You may go to Advanced Techniques if you wish to explore Dominoes further. | ||||||||||
I was a little confused when I updated from the alpha until I noticed that things that used to be ${JSON} have become $(JSON) - there is still an example of the old style in the description of the sub-rule in the "Rules repository" section that may confuse: ${swfObject}
Thanks for your work on this, it's proving to be fantastically useful. The cumulators are exactly what I was trying to work out how to implement in the alpha!
@nevstokes: corrected, thanks for having pointed out the typo :)
Hi, Julian.
I didn't understand if its possibile to handle request erros. What happens if you call an invalid url?
Thank you very much for this and... keep up the great work!
@alberto: no, handling request errors is beyond the scope of dominoes. If one request fails within a chain, then the whole chain will halt which is enough for a script dependencies loader/manager.
And thanks for the kind words, always appreciated :)
I seem to be having issues with getting Lightview to play nicely with Dominoes. Has anybody else encountered this?
@nevstrokes: never used Lightview. What happened exactly? Maybe you should open an issue.
Hey Julian,
Basically everything works if I include each file in a <script> tag but as soon as I try to use dominoes Lightview complains about not having a controller. A hefty segment of the Lightview code has been compressed with Dean Edwards packer - could this possibly be something to do with it?
@nevstrokes: oh yeah, Dean's packer is a nightmare for script tag injection based loaders. Sometimes it works, sometimes it does not.