Welcome, guest Sign In

Video: Chad Auld — Introducing PHP Loader

Video published 2009-10-29.

Transcript:

Chad Auld: My name is Chad Auld, I'm a Frontend Engineer here at Yahoo! I work on the Buzz Marketing team, and I co-authored the YUI PHP Loader with Adam Moore. Today we'll be giving a little introduction to this. It was just recently released several weeks ago, so you may or may not have played with it yet.

So what is it? It's a server-side utility that's useful for loading YUI components onto your page using PHP. It is a standalone component that's not shipped as part of the standard YUI download, although it's downloaded separately from the same place [note: all YUI projects can be downloaded from http://yuilibrary.com/downloads/]. I just want to give you an overview of what the structure of that actually looks like. The API documentation is contained inside the download, same API doc format that you're used to. There are a bunch of examples included with the download. There's a lib directory, and inside this lib directory is a meta-folder. This meta folder contains the metadata that the loader uses to understand how to load components onto the page, and we're going to talk more about that. Then there is the loader itself, and some test suites in here. There's also a combo handler. We'll cover a little bit more about that in a minute.

Why use it? It helps simplify resource selection. It does automatic dependency calculations for you. You can count on it to give you reliable, sorted, loading of those dependencies. It allows for less metadata to be sent over the wire. We'll talk a little bit more about that, but today when you're using the client-side loader we have to support that by sending a lot of metadata over the wire so that the client-side loader understands how to calculate dependencies on the fly. Using the server-side loader we ship that metadata, it's on the server, and so the calculation can be made before it even hits the client.

This one's [inaudible], but it simplifies library upgrades in that you just tell it what version of YUI you use, and you can change that version number without changing any other files because it will figure out the paths to those files. Of course, during upgrade there's obviously more to think of than just the version number, but if it's a simple 2.7 to 2.8 it may be as simple as changing the version number. A change from 2.8 to 3.0 would be a little bit more complex, obviously. It will help you optimize your page load time via things like the aggregate files, the rollups, and either local combo handling or the Yahoo! CDN. Lastly, it will integrate with your existing modules. We're definitely going to go over some examples of that, but you can take custom modules that you've written today and have the loader use those as well. So in addition to being a YUI loader, it's a generic loader that can understand metadata that you give it, and load your own utilities as well.

With dependency calculations, a question you probably have is can't I already do this? You can, and the way you do it today is probably one of two ways. You're either using the dependency configurator, where you basically hand select the components that you want to use and then it generates the copy and paste code for you. There's also a tag for the dynamic loader if you want to use the front side loader rather than copy and pasting the individual files. This slide is blowing up what the copy and paste method looks like. By hand selecting those components, we're going to use these same resources throughout the presentation, just to keep it consistent and less confusing. In that example I selected fonts, resets, grids, tab view, and then also the Yahoo! DOM event element in tab view resources. Typically you'd copy and paste this directly into your document. Another option is to use the front side client loader, where you just load in the loader file and then create an instance of the loader class, passing it the components that you require. This uses that front side metadata that we talked about, that we shipped over the wire to do those calculations on the fly, and then it inserts all that into the page dynamically.

Here's a basic example of how you do this in PHP Loader. All of that becomes four lines of code in PHP. We include the loader, which is the PHP class that does all the magic. You create a new instance of that class, you pass in a string which is the version number of the library that you intend to use, and this corresponds to the metadata that we ship with the component download. We currently ship YUI 2.8.0 and YUI 3.0.0, but we'll continue to make metadata available as new releases come out, and we can always go back if you need it. Then you call the load method, passing in the name components that you want to load on the page. And then you simply echo out one of the methods available is the tags method, and this will grab all of the resources that have been calculated, all of the dependencies, and it will just output them in one shot. Most likely, you would call this tags method in the head of your document since it can output CSS and JavaScript resources, most likely.

What does that actually look like? Same thing we saw before. Instead of handpicking all the components, we've just specified the ones we need, and got the same output. There's the CSS resources, and then our JavaScript resources. I just want to point out that, by default, that's nine HTTP requests that are made.

I want to cover some of the options inside the constructor to that PHP class. The class is YAHOO_util_Loader, and there are four parameters that go into this constructor. The first one is the only one that's required, and we've already seen that that's the YUI version number. This corresponds, again, to the YUI metadata that you intend to load so that it knows how to calculate the dependencies for the page. The second parameter is the cache key. The loader will make use of PHP's APC, the alternative PHP cache, if in fact it's available, so once we do those calculations we can cache that off and then we don't have to do those calculation's addition requests. That will speed up the performance. It is calculated for you, like I said, but you can override it if you have reasons to do that.

The third parameter is a list of modules, so if you need to load any custom modules — I'm going to cover how you do that a little later — it's essentially an associative array of custom modules that you pass in. Finally, there is a metadata flag. If you're just using a generic one and you're not loading the actual YUI metadata or YUI components onto your page, you just want to load custom components, you can tell it that you don't want to include the YUI metadata, and obviously it will just skip loading that.

Here are some of the configuration options that are available to the class. The first one is the base, and this allows you to specify the location for the YUI build directory if you've put the actual library locally on your server and you want to reference that. By default the base path will serve the files from the Yahoo! CDN. There's a filter option. By default, when you load these up you will get the minified version of all the CSS and JavaScript files for performance reasons. But in staging environments or development environments it may be useful for you to pick up the debug files, or the unminified versions of those files, so you can pass a filter with a constant, either the YUI_DEBUG or the YUI_RAW, to pick those up.

There's also an allowRollups. This is on by default for performance reasons. In the original example you saw, we said we wanted Yahoo, DOM, event, reset, font, and grid, so we got six requests in that bit. Here, the loader obviously knows that those three files for the JavaScript can be rolled up into this one, and those three files for the CSS can be rolled up into this aggregate file. The last thing we'll talk about for now is the loadOptional. Some components have optional dependencies because they're common use cases. An example here would be if you selected tab view and you chose to load the optional dependencies, you would also pick up things like the selector, the connection, and a few others. This is off by default.

The question is, do those options seem familiar? They should. If you've used the dependency configurator before, it's basically the same set of options that you see on the dependency configurator — the ability the override the base, to run rollups on or off, to combine files, to change your filter from minified to debugger raw. It's the same idea. We've covered a few of these, so let's get into how it helps to optimize the page load times via rollup files, the aggregate files, and do some combo handling.

In this case it's the same request we made before, but this time we're going to add the allowRollups = true. Again, this is on by default; I turned it off for the first example to make it a little less complex. In this case you can see that we went from nine HTTP requests down to five, which is a 44 per cent improvement just by adding this one flag. Now you can see that with the rollups on, we get the aggregate files for reset-font-grid.css, and yahoo-dom-event.js. Here's an example with the filter. Same request. This time we're passing the filter, and for the JavaScript files there are debug files available. So in this case element will give us a debug, and the tab view will also generate a debug file. Again, this is probably the most useful in a staging or development environment.

I want to cover some of the output methods that are available to the class. We've seen tags before — they're what I've been using throughout — and again, this is one that says give me all the includes, don't hold back. It's probably going to go in the document head, it's going to give you all the JavaScript and CSS resources, and output it in one shot.

We also have CSS and script methods, and as they sound, these will give you more control and allow you to call for just the CSS resources or just the JavaScript resources. This is great because it lets you comply with the standard performance guidelines of putting CSS into the head of the document and JavaScript as low in the document as you can, preferably just before the closing body tag. We have embed, which says give me everything, don't hold back at all. This actually gives you all of the dependencies, all of the code, and just embeds it into the page inside the link or the script nodes. Like embed, or like CSS and script, we have the css_embed and the script_embed. These give you more control like CSS and script did, but it actually gives you all that raw code. Here you can embed just the CSS in the head, and embed just the script down in the closing body. This obviously eliminates the need for some of those HTTP requests to go back out and fetch that later on, as document loads.

There are also a number of other formats that are available and which are useful for more programmatic purposes — perhaps writing your own combo handler, or trying to determine what files go into a component or rollup. One of those methods is data. That will provide you with a PHP array of JavaScript and CSS components, based on the components that you've passed into the load method. You can see the path to the file, and then the components that have gone into creating this. Another method is JSON. This is basically the same as data except that this time we're getting a JSON structure back. Again, you can see it's broken up into JSON and CSS, with the components that have gone into this. We also have raw, which is similar to embed except that it gives you just the raw code, and it doesn't give it to you inside of either the script of link nodes.

I want to put this in context and actually show a full document here on the server. This is where you would do your initial loader setups — creating the instance of the class, passing in the version number that you needed, calling the load method with the components that you actually want to load. In this case, we would be loading calendar. In the head, we'd be calling for just our CSS files, and then just before the closing body tag we would be calling for the script, and then adding in any custom JavaScript we need after that.

What does that look like on the client? Obviously all the calculations are done on the server, but by the time it hits the client it renders you have replaced the call for the CSS with the actual CSS resource, which in this case is calendar. We replace our call for JavaScript with yahoo-dom-event and calendar. Even if we just call calendar and we didn't actually specify that we needed yahoo-dom-event, the dependency calculator would pick those up and would load them in the right order. It knows that it needs yahoo-dom-event to support calendar, so it would load them up, and then it would just have our custom JavaScript that's going to render the calendar into our calendar node.

We'll touch on one last thing here, which is: how do we integrate the loader with your own custom modules? The third parameter to the constructor is that module list of your custom modules. Those are to be given as an associative array. That array should consist of JavaScript and/or CSS modules — it doesn't have to be both, it could be one or the other. The format of these modules mirrors the standard format that's provided by the YUI metadata. There are examples in the documentation for this, and you can also use the metadata that's provided inside the lib meta-folder of your download for seeing all the available options that go with it.

One thing to note is that the module names must be unique. Obviously we don't want any collision between modules. You could potentially re-use a YUI name if you turned the YUI metadata off, but since you may turn that on at some other point, it probably makes sense to namespace these things or name them uniquely so that you don't have any conflicts in the future. Finally, custom module dependencies. Modules can be dependent on other custom modules, say if you have dependencies between your own custom modules, or they can also be dependent on existing YUI modules.

Here's an example of a custom module. We're pulling in our loader class and we're creating an array with three custom modules inside it. Some important things to note on this are that we're going to give it a name, and that's the name we'll later pass to the load method, and we're going to give it a type, either JavaScript or JS or CSS. We can define the full path to this custom module. In this first one, you'll note that there's a required parameter on here, and that is giving a name of another module. We have a JSON module, which will relate to the JSON module that we're defining. Note that even though we define these in a separate order, so the JSON module comes after, because we have the requires flag it knows the dependency, so the loader is smart enough to load them in the proper order even though they're custom modules. Finally, our third one is a custom CSS module with type CSS, and then obviously the full path to that CSS.

The way we actually call these is the same exact way as we called them before, and that's to create a new instance of the loader, pass in the version number for YUI. In this case we've given a cache key. We're passing in as that third parameter our custom module list that we just defined. Then in this case, I'm turning off the last parameter, I'm passing false, I'm turning off the YUI metadata, because in this case we're not using any YUI modules, so there's no real need for it. Then we'd call load, passing in the named parameters that we've given here: JSON module, custom CSS, custom JS. What does that actually look like? We have one CSS resource — that's our custom CSS — and we have two JavaScript resources. One is the JSON utility from json.org, which gives us the parse method. Then we have our custom data file, which is probably some JSON data that we need to parse while we brought in the JSON module.

This is the same example but this time with some YUI dependencies. We call the loader, again we set up our array with two custom modules. This time I've eliminated that JSON module, so instead of pulling in the JSON Utility from json.org we're going to go ahead and use the one that's native to YUI. You'll notice that, in this case, in my requires parameter I've removed JSON module and added that we're going to go ahead and pull in event and DOM and the JSON module in a custom CSS file. Same loader setup. What does this actually look like? Again, we've pulled in our custom CSS file. You'll notice that we've picked up the yahoo-dom-event aggregate file, and we've picked up the JSON module, and our custom module.

We'll talk a little bit about combo handling. The idea is that with the combo handler, the URL will make a single request per resource type — a single request to fetch all of our CSS, another request to fetch all of our JavaScript. We get it all in one shot; we get that single resource back, cacheable. By default we can take advantage of the Yahoo! CDN, and there are a lot of advantages to that with the caching and the geographic placement. If you don't want to use the Yahoo! CDN, and there are reasons some people have for that — we'll talk a bit about some of those in a minute — for whatever reason, the PHP Loader does ship with intrinsic combo handling support. That will allow you to actually do all the combining locally on your own servers without ever going back to the Yahoo! CDN.

Touching on that, one reason that seems to come up quite often on the forums and we'll get questions on is, can the Yahoo! combo handler on the CDN today support SSL? The answer is no, but if you use the local combo handler with PHP Loader and you have SSL configured on your own boxes, then you should be able to get this working without much issue. One thing to note here is that combo handling is currently limited to just YUI modules, so if you attempt to load any custom modules and you attempt to use the combo handler, it's not going to fail, but you won't get the combo URLs, you'll just get the raw resources.

Audience member 1: Unless you build a local [inaudible].

Chad: Correct, that's right. We are hoping down the line to be able to do all of it, but at this point it does not.

Two more configuration options to add to the four we covered initially. One is combine, and this does what we just talked about; it combines all the resources into a single request. It allows you to take advantage of the Yahoo! CDN, or use your own server if you go with the next option, which is comboBase. By default, the comboBase is the http://yui.yahooapis.com/combo? path. If you override this — and I'll show you an example of that — you can override to your own server path to either the included combo.php script, or to your own combo handler that does the same thing, and then the server from the your own servers.

Now we're revisiting our basic example that we covered upfront, but now with combo. allowRollups is true, which is the default, but if we add combine = true, when loading the same set of modules we now get just two HTTP requests. We're down from nine all the way to two, so it's a 77 per cent improvement over where we started. You can see that we've got the rollup files, in this case, two different resources but combined into one. Here we've got the yahoo-dom-event, the element and the tab view, so two requests will give us all the functionality we need for our page.

This is the same example but now with the local combo handler. All we're doing here is setting the comboBase. We're going to set it to the path to the locally included combo.php file, and call for the same set of resources. Again, it's just two HTTP requests, but this time from our custom endpoint. The big different here is you'll note that the starting path no longer points to the Yahoo! CDN, but rather to our own custom event path that we defined in comboBase.

A little bit of background about the combo handler. If you extract the package that you download right into your web server and you put it right into the web route, it's probably fine. If you bury it somewhere else within your server then you'll probably need to open up combo.php, look at the very top of the file for the constant path to loader, and tweak that as needed for your own set up. Outside of that it should just work.

The local combo handler tries to do all the same magic — sets the cache-control, the expires, and the content-type headers, tries to match those that are set on the Yahoo! CDN, and to pick up the same type of performance benefits. Just one note: it makes use of the same metadata and the same core class that all the other examples uses. It just disassembles the URL, tries to construct the right loader calls for you, and then gives you back just that single ball with JavaScript or CSS.

So what does the future hold for PHP Loader? We're working, obviously. Right now we've shipped the first beta and getting feedback from the community. We're working towards the first production release. We're hoping that in the next week or so we can get out a beta 2 with some fixes to that combo script, and just continue driving towards the production release.

In the future we hope to support combo URLs that are shorter. We know that as the library becomes more module, especially how YUI 3 has submodules and whatnot, we know that there are limitations to the URL and we can blow by those even today with some combinations of YUI 3. So instead of specifying the long combo URLs that include the YUI version number with the full base path all the way down to the file, we may hopefully get to a point where we can, say, pass a subversion number, pass us a list of modules that you want to include and then maybe some of the other optional parameters, and then keep that to a very short URL and be able to perform all the same magic that we did today.

The last thing on this point is that this is PHP, but obviously we're hoping that people will help us port this to all the other popular languages out there. If you're not using PHP, or want to use something else, certainly we'll willing to help you as much as we can to get it over to one of these languages. If nobody else picks up Python, I might try. But I'm sure somebody can do it better than me.

That is it.

Copyright © 2010 Yahoo! Inc. All rights reserved. Copyright | Privacy Policy

Help us continue to improve the Yahoo! Developer Network: Send Your Suggestions