When working with FAT client web 2.0 application, it is normally quite slow whenever you need to reload your application because you are developing against unbuilt code (the source files are changed frequently, so you don’t want to build your frontend code every time a modification happens). As a frontend developer, you are using Firefox + Firebug, with console/script tabs enabled (sometimes net tab in firebug as well), which makes the loading time of a page with lots of javascript files even more slower.

While we are used to ajax ways of updating part of a page without reloading the entire webpage, no one seems to apply the same methodology to reloading javascript source files.

Dojo has the powerful dojo.require mechanism which can pull in javascript source files on the fly, and it is smart enough to cache any source files which are already downloaded. However, it does not provide any way to force reloading of a js file.

After digging into dojo.require, I came up with a simple function to overcome this very issue: basically, it will unset any memory dojo has about that downloaded source file (or module, as called in dojo.require), and dojo.require that module again.

Here is the source code for this function, which is called dojo.reload for now:

dojo.reload=function(d){
	//remove the module namespace from its parent namespace
	var sym=d.split('.');
	if(sym.length>1){
		var pname=sym.slice(0,-1).join('.');
		var prop=sym[sym.length-1];
		var parent=dojo.getObject(pname,false);
		if(parent){
			console.log('delete property',prop,'on object',pname,':',delete parent[prop]);
		}
	}
 
	//remove _loadedModules entry so that dojo.require will re-load it
	delete dojo._loadedModules[d];
 
	//tidy up _loadedUrls so that dojo._getText will reload it
	sym=dojo._getModuleSymbols(d);
	var relpath = sym.join("/") + '.js';
	//copied from dojo._loadUri
	var uri = ((relpath.charAt(0) == '/' || relpath.match(/^\w+:/)) ? "" : dojo.baseUrl) + relpath;
 
	delete dojo._loadedUrls[uri];
	dojo._loadedUrls.splice(dojo.indexOf(dojo._loadedUrls,uri),1);
 
	//set cacheBust to make sure we load latest file
	dojo.config.cacheBust=+new Date;
 
	dojo._loadreloaded=d;
	if(!dojo._reloadhotkey){
		dojo._reloadhotkey=dojo.connect(document.documentElement,'onkeydown',function(e){
			if(e.keyCode===dojo.keys.F6){
				dojo.reload(dojo._loadreloaded);
				dojo.stopEvent(e);
			}
		});
	}
	console.log('reloading module',d);
	dojo.require(d);
};

Just copy and paste this function somewhere to your frontend code base, and when you want to reload a particular module, just type dojo.reload('mymodule.myfile') in Firebug console, and the latest version of your module will be downloaded and ready to be used/tested on immediately. In order to make sure the browser does not use one from its cache, cacheBust will be set to current timestamp to make sure it is loading from server directly. Another fine touch in the dojo.reload function is that, if you just want to reload the module you last reloaded, simply hit F6 which saves you some type.

WARNING: this is only meant for development, don’t put this in your deployed code base. This is only tested in firefox 3, but it should work in other browsers as well. I think this will only work with the default loader and it will fail if you want to use it in xdomain case. At last, the famous phrase: use at your own risk.

Edit: fixed mangled greater than symbol (thanks slackorama). changed all this->dojo so that no matter what this function is called, it can always correctly unset any “dojo memory”. – December 2, 2008 at 7:51 am