3

Simple javascript files loader for embeddable javascript application

Problem:

To develop a large scale javascript application, embeddable to pages, the first problem I faced was including large number of javascript files in the page. So like google or yahoo applications you simply include one javascript file and after few lines of javascript to start the application, otherwise you will end up with something like this:

<script type='text/javascript' src='js/jsfile1.js'></script>
<script type='text/javascript' src='js/jsfile2.js'></script>
<script type='text/javascript' src='js/jsfile3.js'></script>
<script type='text/javascript' src='js/jsfile4.js'></script>
<script type='text/javascript' src='js/jsfile5.js'></script>
<script>
     myApp.init();
</script>

You might have a simple, advanced and other versions of your application and the end user will have to figure out (or you have to explain) which files need to be included for different versions of applications. Also it looks ugly and meaningless for the enduser to include a big list of javascript files.

You can simply include all your javascripts in one big file and minify it, but

  • Sometime you want to keep your javascript libraries separate from your code
  • Also you might want to include different number of javascript files depend on which features user want to use. You will never want to load all javascript files if user want to embed just a simple/basic version of your javascript application.

Append script tags to head?

You might be thinking why don’t make an array of javascript files name, loop through this array and than for each file name, make a script tag and append it to the head tag. Well this is the solution but you might be loading external javascript files or host your javascript files outside on a CDN and some javascript files will load slower than others. Your javascript code might be depended on other javascript files, for example if you are loading jQuery library and than all your jQuery plugins, you might get an error “jQuery not defined” in your plugin files because jQuery might take longer to load than your plugins. So your plugins will load first and jQuery will still be loading so it will break your application.

jQuery’s getScript method can be used to load ONE javascript file at a time. You can use it inside a ‘for’ loop and use getScript’s callback to include the next script in an array of script file names. But you would never like to include a whole jQuery library just for this purpose (when you are not using jQuery anywhere else in your application).

Solution:

My idea to embed javascript application is include a single javascript file. Call a function and pass the type of application as argument. The function should make a list of javascript files to include, depend of the type of application and once all js files are loaded, call a callback function. Something like:

<script type='text/javascript' src='js/jsFileIncluder.js'></script>
<script type="text/javascript">
includeJs('basic','',function(){
	yourApp.init();
});
</script>

Demo

Here is the simple script to accomplish this goal, used in above linked demo:

includeJs = function(appType,jsRoot,callback)
{
	var
	//If nothing provided
	appType = appType || '',
	//URL for js files
	jsRoot = jsRoot=='' ? 'js/' : jsRoot,
	//Willl hold a list of all selected js files
	jsFiles = [],
	//Defining different arrays having file names.
	//No need to put .js at the end unless you have server-side generated js files.
	mainLibs = ['jquery.1.4.2','jqueryUi.1.8.4'],
	jqueryPlugins = ['jquery.plugin1','jquery.plugin2','jquery.plugin3'],
	simpleApp = ['appFile1','appFile2'],
	advancedApp = ['appFile3','appFile4','appFile5','appFile6'],
	init = ['init'];

	//Create one big array i.e jsFiles depend on each appType
	switch(appType)
	{
		case 'basic':
			jsFiles = jsFiles.concat(mainLibs, simpleApp, init);
			break;
		case 'simple':
			jsFiles = jsFiles.concat(mainLibs, jqueryPlugins, simpleApp, init);
			break;
		default://advancedApp
			jsFiles = jsFiles.concat(mainLibs, jqueryPlugins, simpleApp, advancedApp, init);
			break;
	}

	//Method: Includes the file to the header
	function scriptIncluder()
	{
		if(jsFiles.length==0)
		{
			if(typeof callback == "function") callback();
			return;
		}
		var file = jsFiles.shift();
		file = jsRoot+file+'.js';
		scriptGetter(file);
	}

	//Start the engine
	scriptIncluder();

	function scriptGetter(url)
	{
		var head = document.head || document.getElementsByTagName("head")[0] || document.documentElement;
		var script = document.createElement("script");
		script.src = url;
		var done = false;
		//Attach handlers for all browsers
		script.onload = script.onreadystatechange = function()
		{
			if (!done && (!this.readyState || this.readyState === "loaded" || this.readyState === "complete"))
			{
				done = true;
				scriptIncluder();
				// Handle memory leak in IE
				script.onload = script.onreadystatechange = null;
				if(head && script.parentNode) { head.removeChild(script);}
			}
		};
		head.appendChild(script, head.firstChild);
	}
}

This script will create any array of js files depend of application type user wants, and will start loading js files in the array. Once a file is loaded, another js file in the array will start loading so you will never get an error if (it should) your javascript code is depended on the code in other js files. Once all the js files are loaded, it will trigger the callback function to start your application.

Improvements you can make:

This script is totally customizable, depends on how you are loading the js files. You might be including some external js files or some server-side generated js files with ‘.aspx’ or ‘.php’ at the end of the files. So you will have to change the script to fullfil your needs. But basically ‘scriptGetter’ method will remain as it is, you just need to prepare an array of your javascript files according to different type of your applications.

Shortcomings:

  • No error handling if js file not found (404 error). You have to check in developer toolbar if js files are loaded correctly. You can also look at the ‘scriptGetter’ method and look for other states, for details see this and this
  • Need to add files to the arrays, every time you add a new js file to your application. You can customise this script where you will have to pass an array of js files to this method but it will increase the number of lines of code and end user has nothing to do with the that list of files.

Links:

Demo Demo script

3 Responses

  • March 22, 2011 at 9:56 pm

    hey aamir,
    very nice post :) have you ever checked lab.js and yapnope for script loading.

    Best Regards,
    najam

    • March 22, 2011 at 10:04 pm

      Hi Najam,

      Yes i did try all these libs plus some other.

      This one is not a plugin but just a script which can be combined with server-side code to make arrays of js files depend on different types of js applications.

      I wrote this script specifically for ishare (isharemaps.com) applications, so with this script all you need is the application name like:

      includeJs('ishareBasic','',function(){
      ishareApp.init();
      });

      or

      includeJs('ishareFull','',function(){
      ishareApp.init();
      });

      For small scale js applications where you don’t have to add or remove js files frequently than the lab.js and yapnope are better options.

      Most importantly, I learnt a lot while writing the script and understanding how it work :P

  • mohammad waseem
    April 24, 2012 at 11:21 am

    hello aamir,
    i want to develop a chart whose points are drag-able means we can drag the points up and down and the color of point should be change according to our action.. if i drag a point below to its base line then color of point should change to red from yellow,,,
    any help will be highly appreciable. please help me… thanx in advance… n i am using $.jqplot.Draggable plugin.

Leave a Reply

*
*
*

* (Just for the spam protection)

Copyright © 2012 — musings of Aamir Afridi
Aamir's QR code