Skip to content

Instantly share code, notes, and snippets.

@wesleytodd
Created November 7, 2012 16:31
Show Gist options
  • Save wesleytodd/4032642 to your computer and use it in GitHub Desktop.
Save wesleytodd/4032642 to your computer and use it in GitHub Desktop.
The White Lion Javascript Library

The White Lion Javascript Library

Important Architecture Choices

  • Modularity: All portions should be stand alone, utilizing the module pattern and dependency injection.
  • Separation Of Concerns(SOC): Using templates and configuration options we need to keep DOM manipulation, HTML, and CSS to a minimum inside the hard-coded JS.
  • Configurability: Nothing can be mandatory, no more "hi-jacking" events or forcing features. All modules and plugins need to be configurable on a site by site basis with logical defaults.
  • Asset Lazy-Loading: Minimize the up-front footprint on page load, relying on loading assets and modules in a way that increases responsiveness.
  • Easy Interface: The interface needs to be easy to use and well documented so that new hires can quickly come up to speed with the available features and best practices.

Questions

  • Why no build step? Require JS provides a great tool for concatenating and minifying Javascript files. It has become very popular as a way to organize large and modular code bases and push them to a production build. For simplicity, one command seems much more simple that a complicated asset manager that builds and caches code on a live site. Nothing can be simpler than serving a static file. Just being new does not mean it is more complicated.
  • How are we going to handle versioning and bugs? I think that each module should be versioned separately, that way when we find a bug we only have to update and worry about one portion of integration code. I also think that moving these to GitHub would be both a great way for team members to learn git, as well as enable the great features like bug reports, change visualization and possibly, someday, as a promotional tool for White Lion.

Learning Points

What is the 'Module Pattern'?

The module pattern is a way to encapsulate code so that it can be re-used and maintained without variable collision or messy code-bases. Here is a basic example of the module pattern:

var ModuleName = (function(dep1, dep2) {

	// Module Constructor
	var Module = function() {
		
	}
	
	// The rest of the module goes here

	// Return the module to the outer scope
	return Module

})(dependancy1, dependancy2);

To break it down a bit, the first line is declares a variable, ModuleName, which will receive the return value of a function. This function is an example of an 'Immediately Invoked Function Expression', or in more common Javascript terms, an 'iife' (pronounced 'iffy'). The IIFE ensures that the variables inside are not accessible in the global scope, this is called a 'closure'. Closures are formed by any function and are due to the fact that Javascript has lexical scope. The most basic example of an IIFE is:

(function(){     //Create an anonymous function
	
})();            // Call the anonymous function

The return value from the anonymous function will be passed out into the variable and thus become available in the global scope for you to use.

How do I use template instead of hard-coding the content

Using Underscore this is simple:

<!-- Create a template -->
<script type="text/template" id="my-template">
	<li><%= content %></li>
</script>
<!-- Use the temlate -->
<script>
	var tmpl = _.template($('#my-template').html());
	var $ul = $('<ul />');
	_.each(items, function(item) {
		$ul.append(tmpl(item));
	});
	$('body').append($ul);
</script>

What we are doing here is defining a template that will be used later inside a script tag. By giving the script tag a type of text/template, we have said that the template should not be parsed as Javascript. Then we can grab that template's content using jQuery, $('#my-template'), and pass it into the _.template function. This function returns another function, an example of a Higher Order Function. The function that is returned should accept an Object that is a hash of key/value pairs matching the variables inside the template. So item.content should have a string that will be placed where the <%= content %> tag is placed. There are many more complex things that you can do with Underscore template, see here for more information.

If the project does not require Underscore, then a template implementation might be necessary inside a module. Here is a really basic implementation for a template system:

var Template = (function(){
	return function(t){
		if(!(this instanceof Template)){
			return new Template(t);
		}else{
			var me = this;
			me.template = t;
			return function(data, container){
				var out = me.template;
				for(var key in data){
					out = out.replace(RegExp('{{' + key + '}}', 'g'), data[key]);
				};
				if(typeof container != 'undefined'){
					container.innerHTML = out;
				}
				return out;
			};
		}
	};
})();

This implementation uses the module pattern and returns a function that takes a template/string as an argument and returns a function that takes a hash of values to interpolate into the template. This can be included inside a module, or passed in as a dependancy to another module. If a module requires a templateing system, you can define an interface for the templating system and pass it in using dependancy injection:

var MyModule = (function(templates) {

	if (typeof templates !== 'function') {
		throw TypeError('The templates variable must be function');
	}

	// the rest of your module

})(_.template);
@wesleytodd
Copy link
Author

I added a features list to the original location of this post: https://github.com/wesleytodd/Thoughts/blob/master/code/wl-js-library.md

Once we are all added to the new wlion account I will move this all into private repo there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment