Gal Segal's Blog

Thoughts of a programmer with a soul

Dec 19

Javascript Modules Infrastructure

Tags:

Infrastructure_by_FluxSys

Working on a website with a lot of JavaScript code can be somewhat challenging, especially if most of the functionality comes in the form of Ajax. We see a lot of best practices for building individual plugins, creating private methods and members, and exposing a public and consistent API outside. Finding some tips about managing several plugins or modules together is a little bit harder. I needed some mechanism that will help me control the creation and manipulation of JavaScript  modules,  and after some digging I decided to write it myself.

The main motivation for this mechanism arose when I noticed that managing the JavaScript portion of a website I am currently developing at work became a complex task. Each developer had his one idea about the structure of a module he created, the way it works internally and how it should communicate with other modules.

This Infrastructure is a suggestion for managing multiple modules together. It establishes a baseline for module creation and basic functionality, determine the module life cycle events and defines ways of communication between modules.

These are the main principles I wanted to achieve:

  1. Creation of modules: The infrastructure (an object named “modulesCoordinator” or MC for short) will handle the creation of all modules, thus establishing a simple baseline for all modules that live on the page.
  2. Module Structure: Each module has 4 basic methods: init, start, stop, dispose. These methods shows the life cycle of a module, and can be overridden (they are all empty functions), or ignored.
  3. Module Extensibility: Each module can have it’s own unique methods, both private and public, as well as private members.
  4. Other libraries integration: All the infrastructure code does not relay on any external JS library (jQuery, MooTools etc), but can work along side these libraries. I work with jQuery, so I implemented a jQuery plugin (see tests).
  5. Central Control: A key ingredient in the infrastructure is the MC object, which registers all the modules and expose several methods for communication with a single module or all the modules at once.
  6. Availability: The MC object is a global variable, thus can be reached from anywhere on the page, as well as from inside the modules themselves: each module has a member referencing the MC.
  7. Performance: The infrastructure is lightweight and tries not to interfere with the rest of the code. All methods are as thin as possible to avoid performance issues.

So, lets look at some code. First, a basic module structure:

var baseModule={
	mc:modulesCoordinator(),
	name:'',
	init: function(){},
	start : function(){},
	stop : function(){},
	dispose: function(){}
};

and module creation:

create:function(module){
	if(module == undefined || module.name === '' || module.name === undefined){
		logger.warn('cannot register a nameless module');
		return;
	}

	var baseModule={
		mc:modulesCoordinator(),
		name:'',
		init: function(){},
		start : function(){},
		stop : function(){},
		dispose: function(){}
	};

	var newModule = extend(baseModule,module);
	regsiterModule(newModule);
	return newModule;
}

Each module has to have a unique name, by which it is identified. Creating a module with an existing name or without a name will fail.   Each new module will be merged into the the baseModule object, inherit all methods and member and override whatever it wants. This way all modules will the same basic characteristics has well as unique ones.

These are the MC public methods:

get: function(name){
	logger.info("Getting module " + name);
	var moduleIndex = isModuleExist(name);
	if(moduleIndex ==  -1)
		return;
	return modules[moduleIndex].instance;
},
initAll:function(){
	activateAll('init');
},
startAll:function(){
	activateAll('start');
},
stopAll:function(){
	activateAll('stop');
},
removeAll:function(){
	logger.info('removing all modules');
	modules = [];
},
startSingle:function(name){
	return activateSingle(name, 'start');
},
stopSingle:function(name){
	return activateSingle(name, 'stop');
},
activateSingle:function(name, action, args){
	return activateSingle(name, action, args);
},
removeSingle:function(name){
	var moduleIndex = isModuleExist(name);
	if(moduleIndex !=  -1){
		logger.info('Removing module '+name);
		modules.splice(moduleIndex,1);
	}
},
print:function(){
	logger.info("Printing modules:");
	for(var i=0, l=modules.length; i<l; i++){
		logger.log(modules[i].name);
	}
}

The methods are pretty self-explanatory,and all the logging are just for testing, but I’m sure you get the idea.

Lastly, The MC object is a singleton, and once created, will always return the same insatnce.

You can download the code and use it as you please.

Enjoy!

Back to top