home > yui > demos

Using Groups with the YUI Loader

Note: This demo only applies to YUI 3.1.x and above


There seems to be a good deal of confusion regarding the new groups feature that was implemented into the YUI Loader config settings. This demo will attempt to clear up some of the misconceptions of what groups is used for and when you might need to use it.

Demo

Whenever you see this [...] it is not actual code; it means the url has been truncated for style purposes


Getting Started

First thing to get out of the way is that this is not a sexy topic of discussion. Nothing is going flying across the screen doing all sorts of killer fx. However, if loading your site as efficiently as possible gets you excited then read on. The YUI loader is extremely powerful and the config settings that are provided to us are extensive and allow us a lot of flexibility over how we handle the processing of our pages.

Loading from the CDN

The groups setting is not necessary if you are wanting to simply load a gallery module that has been pushed and resides on the YUI CDN. All you need to do is include it in your use statement just like you do with any other module.

YUI().use('gallery-yquery', function(Y) {
	Y.log( Y.Env._attached['gallery-yquery'] );
});
						

So if I were to run this code I would see one of two things, I'd either see 'true' or 'undefined'. Below you should be seeing 'true' if our module loaded correctly. Also you will be seeing the base location of where this module was loaded from.

Ok so now onto the groups setting. Groups in its most simplistic explanation is simply an extension or a wrapper of the modules setting. The modules setting is more or less an override. Modules allows you to specify certain parameters about where and how that particular module should be loaded. So in turn groups effectively allows you to override multiple modules without having to define your combo and path settings every time. Let's dig a little deeper for how this may be useful.

Loading multiple modules prior to 3.1.x

Let's say I have a directory structure that looks like this on my server

The library directory is where I have my core YUI files and in those other 3 directories I have my modules I want to load. I'm going to setup my config to only use the modules settings since that's what was available to us prior to the release of 3.1.x

YUI({
base : 'http://kickballcreative.com/yui/demos/loader-config-groups/library/',
modules: {
       'gallery-yquery': {
           path: '../utilities/gallery-yquery.js',
           requires: ['get','event']
	},
	'gallery-yuisand': {
           path: '../animation/gallery-yuisand.js',
		requires: ['anim']
	},
	'gallery-markout': {
           path: '../markup/gallery-markout.js',
		requires: ['dom-style','selector','node-base']
	},
	'gallery-effects': {
           path: '../animation/gallery-effects.js',
		requires: ['node','async-queue','anim']
	}
}
}).use( 'gallery-yquery',
		'gallery-yuisand',
		'gallery-markout',
		'gallery-effects',
		function(Y) {

	// Do module stuff here

});

Not terrible but as our list of modules begins to grow this can quickly become undesired as we are making more and more http requests to load our different modules. This is the beauty of groups and the real power behind it. As our application continues to grow we can group sets of modules and instead of making separate http requests for each one YUI will combo them together into a single request.

Onto the code. This part will be rather long so I'm going to break it down more than I have up to now.

Setting up a combo service

The first thing to be aware of is that we are working off the assumption that you have a combo service in place on your server. I've gone ahead and set one up for this example so I will briefly go into the steps for that before we begin. For those that already have a combo service in place or don't need instructions feel free to skip over this part as it will be of no use to you.

I started off by downloading and moving minify to a directory called 'combo' in the root of my server. Once you've done this open up you're combo folder that you created and you should see something similar to the picture below.

I'm going to open the config.php file and make sure the settings look good for my particular server configuration. The only line I ended up editing for this example was

$min_serveOptions['minApp']['maxFiles'] = 50;

The default is 10 but you can change to whatever you want. I set mine to 50 for now. Once you have your config file setup and combo up and running you can test it out by going to

http://www.yourdomain.com/combo/?f=path/to/a/js/script/on/your/server

This is making the assumption that you uploaded the minify files to a folder called combo in the root of your server

If it loads the script then you're in business.

Minify comes with 2 settings out of the box that you can set via query string and I utilized both of them in my setup. You can set a base path for combo to use as the lookup point for all your files and the other one which is required is the list of files to minify into a single file.

[...]/combo/?b=path/to/buildfrom&f=scripts/to.js,load/separated.js,by/commas.js

Minify is fickle so note that there are no forward slashes at the front or the end of my paths


Loading modules in groups with 3.1.x

Ok so now that we have that portion up and running let's start setting up our YUI config file. Once again we'll take it in chunks.

First thing we are going to do is setup our core config settings

YUI({  
base : '[...]/yui/demos/loader-config-groups/library/',
combine : true,
comboBase : '[...]/combo/?b=yui/demos/loader-config-groups&f=',
root : 'library/',

I setup the base to load from the library folder that I showed you in the image above. I set combine to true since I'm going to be using my combo loader. I set my comboBase path the way I described in the previous step. And last I setup my root path as once again the library directory. Now pay attention to this next part as its critical to make our setup function.

filter : {
	'searchExp': '(^(?:[^&]+&[^&]+)|[^&]+)&', 
	'replaceStr': '$1,'
},

So what did we do there? Well in case you hadn't already noticed, YUI combo handler uses the ampersand & as the delimiter for the combo loader, however, minify uses the comma as their delimiter. Fortunately the YUI guys anticipated this issue and gave us the filter setting so we can change this on the fly. So what I did was setup a regular expression that will filter out the ampersands and replace them with commas so when we pass our querystring to our comboloader it will be correct.

I imagine some may see this and say why not just do this

filter : {
'searchExp': '&', 
'replaceStr': ','
},

And the reason we can't do that is because we then filter out the

&f=

and it turns into

,f=

which as you can imagine this does not work. I won't go into the details of how that RegEx works but it leaves &f= alone and only changes out the ampersands that appear after that point and replaces them with commas

Now we are finally to the whole point of why you're here. The groups setting. Let's go ahead and setup our first group.

groups : {
	utilities : {
		root : 'utilities/',
		combine : true,
		comboBase : '[...]/combo/?b=yui/demos/loader-config-groups&f=',
		modules : {
			'gallery-yquery' : {
				path : 'gallery-yquery.js',
				requires : ['get','event']
			}
		}
	},

This first group I called utilities, you are free to name these whatever you like. Inside it I set the root path to the utilities folder. Once again I set combine to true and comboBase to the combo loader.

This is something important to highlight about groups. Each group can have its own combo setting. So for instance if for some reason you had some scripts that you did not want combo'd together you could stick them into a group and set combine to false and when you called them they would be loaded with their own http request.

The last thing I did was setup the modules for that group. For this example I only have one module in the utilities group but you can have as many as you want. You need to set both the path and the requires and you are done setting up your first group.

Now we will setup our last 2 groups

animation : {
	root : 'animation/',
	combine : true,
	comboBase : '[...]/combo/?b=yui/demos/loader-config-groups&f=',
	modules : {
		'gallery-effects' : {
			path : 'gallery-effects.js',
			requires : ['node','async-queue','anim']
		},
		'gallery-yuisand' : {
			path : 'gallery-yuisand.js',
			require : ['anim']
		}
	}
},
markup : {
	root : 'markup/',
	combine : true,
	comboBase : '[...]/combo/?b=yui/demos/loader-config-groups&f=',
	modules : {
		'gallery-markout' : {
			path : 'gallery-markout.js',
			requires : ['dom-style','selector','node-base']
		}
	}
}
	

We did the same thing in these 2 groups and you'll notice animation has 2 modules loading into it. Now in the use() function we can call our modules one by one to get a better idea of the loading process. First up we will call gallery-yquery

Y.use( 'gallery-yquery' );

That is an image from the console after calling galler-yquery. We were able to turn a 7 http request call into a 1 http request call. That alone is pretty powerful. And now that all those dependancies are loaded anything that requires them from here on out will have access to them without having to include them in their http combo request.

That is what it looks like if I change combine to false and let it load them on individual http requests. Quite a difference. Now we can take a look at the resource load time. This first image shows the time it takes to load with combine set false and making the 7 individual http requests. The second image shows the time it took to complete all the http requests.

This is what it was after changing to load just the one combo'd file. Not a terribly huge difference but we are loading a single gallery module and its dependencies. As our project or application grew you can see how this would begin to account for significant savings in the speed and efficiency of your site.

Pattern Matching

The last thing I'm going to cover is pattern matching for your groups. Let's imagine that we have a directory called gallery and within this gallery we have all of the gallery modules we are going to use for a particular portion of our site.

Now it doesn't make sense to have to list all of these out one by one since we want to just be able to use the whole folder at will. Thanks to the pattern matching we can do just this. One thing to be aware of when doing pattern matching is that it is only checking the pattern against a prefix. In the future this will support RegEx to make it even more powerful but for now we are checking prefixes.

YUI({
	base : '[...]/yui/demos/loader-config-groups/library/',
	combine : true,
	comboBase : '[...]/combo/?b=yui/demos/loader-config-groups&f=',
	root : 'library/',
    groups : {
		gallery : {
			base : '[...]/yui/demos/loader-config-groups/gallery/',
			root : 'gallery/',
			combine : true,
			comboBase : '[...]/combo/?b=yui/demos/loader-config-groups&f=',
			patterns: {
				'gallery-' : {
					configFn : function( me ) {
						me.path = me.name + '.js'
					}
				}
			}
		}
	}
}).use( function(Y) {

	Y.use( 'gallery-yquery' );

});

We've tackled everything else that is going on there but you'll now see we added a patterns setting to my group called gallery (that can be called anything). Notice that I did not specify any modules in my groups just the pattern match. So when I call a module with the prefix of 'gallery-' it will check and attempt to load that module from the settings provided. I also added a configFn setting that can allow you to override the module settings for those patterns.

So now if I call

Y.use( 'gallery-yquery' );

It will match the 'gallery-' to my pattern and load the module from my gallery directory and it will do this for any prefix of 'gallery-'

Y.use( 'gallery-yquery', 'gallery-markout', 'gallery-effects', 'gallery-yuisand' );

All of those modules will be loaded from my gallery directory even those that I never specifically setup in the config.

Summary

I hope this demo helps to clear the air for how and when the groups setting should be used. Full source code for the groups settings example is below and to view all the code from my examples just check out the source of this page its all up in the head for you to grab, tweak, and play with. Enjoy.

Code

Whenever you see this [...] it is not actual code; it means the url has been truncated for style purposes

YUI({
	base : '[...]/yui/demos/loader-config-groups/library/',
	combine : true,
	comboBase : '[...]/combo/?b=yui/demos/loader-config-groups&f=',
	root : 'library/',
	filter : {
	'searchExp': '(^(?:[^&]+&[^&]+)|[^&]+)&', 
        'replaceStr': '$1,'
	},
    groups : {
		utilities : {
			root : 'utilities/',
			combine : true,
			comboBase : '[...]/combo/?b=yui/demos/loader-config-groups&f=',
			modules : {
				'gallery-yquery' : {
					path : 'gallery-yquery.js',
					requires : ['get','event']
				}
			}
		},
		animation : {
			root : 'animation/',
			combine : true,
			comboBase : '[...]/combo/?b=yui/demos/loader-config-groups&f=',
			modules : {
				'gallery-effects' : {
					path : 'gallery-effects.js',
					requires : ['node','async-queue','anim']
				},
				'gallery-yuisand' : {
					path : 'gallery-yuisand.js',
					require : ['anim']
				}
			}
		},
		markup : {
			root : 'markup/',
			combine : true,
			comboBase : '[...]/combo/?b=yui/demos/loader-config-groups&f=',
			modules : {
				'gallery-markout' : {
					path : 'gallery-markout.js',
					requires : ['dom-style','selector','node-base']
				}
			}
		},
	}
}).use( function(Y) {

	Y.use( 'gallery-yquery' );

});