ASAP Loading with LABjs
Plan 1
Let’s start off with some dull code to introduce the subject:
base_url = 'http://localhost/';
//]]>
function loadfile(filename, filetype){
if (filetype=="js"){
var fileref=document.createElement('script')
fileref.setAttribute("type","text/javascript")
fileref.setAttribute("src", base_url + 'js/' + filename + '.js')
}
else if (filetype=="css"){
var fileref=document.createElement("link")
fileref.setAttribute("rel", "stylesheet")
fileref.setAttribute("type", "text/css")
fileref.setAttribute("href", base_url + 'css/' + filename + '.css')
}
if (typeof fileref!="undefined")
document.getElementsByTagName("head")[0].appendChild(fileref)
}
A typical base template for loading the CSS and JS files using Django:
<script type="text/javascript">
var css = {% block css %}{% endblock %};
for (i in css) {
loadfile(css[i], 'css');
}
</script>
<!-- JS Files -->
<script type="text/javascript">
var js = {% block js %}{% endblock %};
if (navigator.userAgent.indexOf('MSIE') != -1){
js.unshift('iespecial');
}
for (i in js) {
loadfile(js[i], 'js');
}
</script>
The actual template for the page specifying the files only needs to be two lines long:
{% block js %}['jquery', 'yui', 'dojo']{% endblock %}
As the bootstrapping code cannot use any libraries itself, this is definitely as manageable as it gets, unless you prefer to merge CSS and JS files into one array. That would acually add more bloat with the ‘.css’ and ‘.js’ extensions. Except there’s just one minor bug with the smaller files being loaded first, resulting in “Uncaught ReferenceError: $ is not defined” for JQuery’s document ready.
Plan Z
The problem with the above scheme is that the files are loaded asynchronously, all at the same time. The usual script tag loading ensures the files are loaded in order. So is there a way to load them asynchronously and still make sure dependencies are met?
The idea is to check document status for complete, then load files that depend on them. LABjs does just about everything I expected. Except it wouldn’t load itself. So to put it all together, I used a mini-loader for LABjs itself. The design decision here is to keep the code As Short As Possible. Code for generating script tags only fits into the template in the MTV pattern. Naturally, JavaScript turns out to be be the best way to load JS files, offering more features than traditional loading schemes with server generated headers. Now, this is all I have to manage with the dependencies:
.script(get_abs_url('framework')).wait()
.script(get_abs_url('plugin.framework'))
.script(get_abs_url('myplugin.framework')).wait()
.script(get_abs_url('init'));
{% endblock %}