Getting Geeky With YSlow

I spent a good amount of time over the last couple of days attempt­ing to make my site a little bit faster. I’ve been pretty neg­li­gent about it up until now, because I know that much of the slow­ness of my site can be directly attrib­uted to my web host­ing com­pany. 1 Even so, I decided to spend some time doing what I could to speed things up.

The first thing that I did was run a test in YSlow to see how my site was doing. Yikes! I got an F right off the bat. After some fur­ther review and research, I real­ized that this wasn’t nec­es­sar­ily some­thing that should have me freak­ing out. If you’re not entirely famil­iar with YSlow and what it does, Jeff Atwood’s arti­cle, “YSlow: Yahoo’s Prob­lems Are Not Your Prob­lems” on Coding Horror is a must-​read. Basi­cally, YSlow offers a lot of good advice that should be taken, but with a grain of salt.

With that said, here are the steps that I’ve taken to speed up my site.

Make Fewer HTTP Requests

The first time I ran YSlow, I dis­cov­ered that all of my pages were making a ridicu­lous number of HTTP Requests for JavaScript and CSS files. I was request­ing four CSS files: screen, print, IE hacks, and one for Light­box 2. Unfor­tu­nately, the IE hacks stylesheet is still nec­es­sary. Obvi­ously the screen an print ones are as well. After taking a look at the Light­box 2 CSS file, I decided that it was small enough to simply tack on to the bottom on my exist­ing screen stylesheet. That’s one down.

There were also quite a few JavaScript files being requested, includ­ing all of the files for Google Ana­lyt­ics, Mint, WP Stats and Light­box. What can I say? I like my track­ing software.

The first thing that I decided to do was to reduce the number of track­ing util­i­ties I was using to two. I love Mint and Google Ana­lyt­ics seems to be nec­es­sary, so I had to get rid of WP Stats. That wasn’t such a big deal for me. That’s another one down.

The next step was to take a long hard look at Light­box 2. I orig­i­nally installed this for my Gallery page, and then decided to include it on all my pages on the off chance that I might want to use it in a few posts. While it works and looks great, I’ve been decid­edly unhappy about how much bag­gage Light­box comes with. There are five JavaScript files that need to be included, just to have that neat little image trick. Even worse, the included Pro­to­type JavaScript library weighs in at a stag­ger­ing 124KB. What a waste.

I made a mental note to do some research to find a more light­weight solu­tion for my image gallery. Smash­ing Mag­a­zine has a good list of them, which I will inspect at a later point in time. For the time-​being, I com­pressed the Javascript files and was able to bring the total size of the Javascript files down to about 125KB from 196KB. I also decided to only include the scripts on my actual Gallery page. It seems like too much of a waste to require all those files when I rarely use them.

Put CSS At the Top and JS at the Bottom

When I first set up Light­box, I wanted to avoid using a Word­Press plugin for it, so I cooked up my own method of includ­ing it. Most of the work was simply trying to find a way around hard-​coding my tem­plate direc­tory in it and also using a func­tion to keep my header.php file clean and easy to read.

The first prob­lem with my orig­i­nal method was that all of those JavaScript files were at the top of the page, mean­ing that almost 200KB of JavaScript had to be loaded before any of the con­tent on my page started to load. That’s no good! The sim­plest thing to do was to move my func­tion down to the bottom of the page, right before the scripts for Google Ana­lyt­ics and Mint. The only other prob­lem was that the func­tion included the CSS file as well. Since I had already decided to merge the Light­box CSS with my main CSS, all I actu­ally had to do was remove the call to load the CSS.

Use Google’s APIs

Unless you’ve been living under a rock (or just don’t care), you’ve prob­a­bly heard that Google just released their AJAX Libraries API. This was pretty much per­fect timing for me since I was already look­ing at how Light­box used the Pro­to­type Frame­work and Scrip­tac­u­lous Effects Library. It makes a whole lot more sense to use a ver­sion hosted by Google than it does to require clients to down­load the same exact ver­sion of a stan­dard library from my slow web host. Ajax­ian has a good run­down of the fea­tures of this new API and why you would want to use it.

After doing a rel­a­tively quick setup, I was able to call the Pro­to­type frame­work from the Google API. It came in from Google at only 29KB; that’s the same file that I was just com­plain­ing was 124KB. That’s a no-​brainer. Scrip­tac­u­lous was a bit more of a prob­lem though, since it takes a mod­u­lar approach. Light­box 2 actu­ally only uses two of the eight pos­si­ble mod­ules. As far as I can tell, there is no way to use the stan­dard type of of script tag to only include the libraries you want like this:

<script type="text/javascript" src="http://blog.nerdstargamer.com/wp-content/themes/positiveGrey-v2.0/js/scriptaculous.js?load=effects,builder"></script>

One of the com­ments on Ajax­ian by jdal­ton, addresses this:

Another issue google will need to work out is that MooTools, Scrip­tac­u­lous, and Dojo are mod­u­lar (mean­ing you don’t have to load the kitchen sink and can just load the parts you want). This can effect the file size foot­print as well. This may be beyond the scope of a CDN though.

Because I couldn’t find a way to only include the mod­ules I needed, I decided to con­tinue serv­ing them locally instead. So, my func­tion to include Light­box now looks like this:

function AKM_include_lightbox() {
    $templateDir = get_bloginfo('template_directory');

    $output = <<<EOT
<script src='http://www.google.com/jsapi'></script>
<script type="text/javascript">
    var tplDir = "${templateDir}/images/lightbox/";
    google.load('prototype', '1.6.0.2');
</script>
<script type="text/javascript" src="${templateDir}/js/scriptaculous.js?load=effects,builder"></script>
<script type="text/javascript" src="${templateDir}/js/lightbox.js"></script>
EOT;

echo $output;
}

Reorganize Template Directory

Although this doesn’t actu­ally have any­thing to do with the speed of my web­site, it seemed appro­pri­ate to take this oppor­tu­nity to reor­ga­nize my tem­plate direc­tory a little bit. I was striv­ing to create a more tra­di­tional web setup within my Word­Press tem­plate that included all CSS in a CSS folder, JavaScript in a JS folder, and images in an image folder.

This first issue to address was the Word­Press default style.css file. This file is nec­es­sary for Word­Press tem­plate to func­tion prop­erly, as explained in the Word­Press Theme Devel­op­ment Codex page. What I decided to do was to remove all of the actual styles from this file and simply leave the Word­Press information:

/*
Theme Name:Positive Grey
Theme URI:http://nerdstargamer.com
Description:A simple theme using a fluid 2 column layout with green and grey
Version:2.0
Author:Alissa Miller
Author URI:http://nerdstargamer.com
*/

/* See css/screen-x.x.css for styles */

I then moved all of the styles to a new file called screen-x.x.css in the CSS folder. This allows me to have all stylesheets (with the excep­tion of style.css) in the CSS folder. It also allows me to use ver­sion­ing in the file­name, which as we will see, will be impor­tant after I’ve imple­mented better caching and expires headers.

I pre­vi­ously put all of the Light­box files in their own folder, to keep things neat. I’ve now decided to roll those files into the normal direc­tory struc­ture instead of keep­ing them sep­a­rate. The CSS file got merged with screen.css and all of the Light­box JavaScript files got moved into the js folder. Light­box also includes sev­eral images, which I decided to put in images/lightbox/ so as not to con­fuse them with my own tem­plate images.

Gzip Components, Improve Caching

One of the rules for YSlow includes Gzip­ing com­po­nents. Some of my scripts are for Mint and JavaScript, which I can’t really con­trol. The others how­ever, along with my CSS are fair game. I had a little bit of trou­ble fig­ur­ing out how to do this since I did not want to use any of the more common php meth­ods to com­press my pages on the fly and was look­ing at just using either mod_gzip or mod_deflate. The YSlow page gives the fol­low­ing information:

Gzip­ping gen­er­ally reduces the response size by about 70%. Approx­i­mately 90% of today’s Inter­net traf­fic trav­els through browsers that claim to sup­port gzip. If you use Apache, the module con­fig­ur­ing gzip depends on your ver­sion: Apache 1.3 uses mod_gzip while Apache 2.x uses mod_deflate.

After some research, I fig­ured out that my web­site is hosted on Apache 2 (not ear­lier). I included this block in my root .htaccess file:

# GZIP CSS AND JS
<IfModule mod_deflate.c>
 <FilesMatch "\.(js|css)$">
  SetOutputFilter DEFLATE
 </FilesMatch>
</IfModule>

I also decided to make the move to using WP Super Cache instead of WP Cache. WP Super Cache is much like WP Cache but does offer some per­for­mance ben­e­fits. Once I got WP Super Cache con­fig­ured and run­ning, it seemed to have an imme­di­ate effect on the speed of my blog. Of course, that could have just been wish­ful think­ing on my part.

Add an Expires Header

One of the last things I did was add an expires header in my root .htaccess file. This tells the client browsers not to look for a new ver­sion at all if the one in their cache hasn’t expired yet.

Now, I obvi­ously don’t want to do this to the dynamic Word­Press files (com­ments and posts would never update!), but that’s okay because WP Super Cache is taking care of those files already. What I do want to do is add the expires header to all of my images, JavaScript and CSS files. None of these will really change except for the CSS files. For­tu­nately, when I reor­ga­nized my tem­plate files, I gained the abil­ity to append ver­sion num­bers to my CSS files. So now I can go ahead and add that expires header to my CSS files, and then simply change the file name when I need to make changes in my CSS. The new file will down­load like normal, and it’s good prac­tice to get some sort of ver­sion­ing underway.

Here is the code that I put in my .htaccess file:

### ADD FAR OUT EXPIRES HEADDER TO STATIC CONTENT ###
<ifmodule mod_expires.c>
  <filesmatch "\.(jpg|gif|png|css|js)$">
       ExpiresActive on
       ExpiresDefault "access plus 1 month"
   </filesmatch>
</ifmodule>

After some thought I decided that one month was an appro­pri­ate length for my pur­poses. This depends entirely on what type of con­tent it is, and how often you are going to change it.

After doing all of the pre­vi­ously men­tioned fixes, I had improved the page load time quite a bit for most of my site. The only remain­ing bot­tle­neck seemed to be my Gallery page. That wasn’t par­tic­u­larly sur­pris­ing con­sid­er­ing that the page includes 25 thumb­nail images. The total size of all of the images, at full size, weighs in at a hefty 2MB. This page was also still using the Light­box scripts.

One of the things I noticed while using YSlow was that some of my thumb­nail images seemed to be unnec­es­sar­ily large. Some of them were as big as 40KB for a 150×150 pixel image! Upon fur­ther inspec­tion I decided that all of the thumb­nails were too large. I had used WordPress’ fea­ture to auto­mat­i­cally create thumb­nails of images to set this up. I’m not sure exactly how Word­Press does this, but after taking a look at the file sizes I’m sure that it sucks. I recre­ated all of the thumb­nails in Pho­to­shop and the biggest one is now only 17.6KB.

I had also orig­i­nally set up the gallery page in WordPress’ admin screen (using the file browser and things like that). Once I was no longer using the dynam­i­cally gen­er­ated thumb­nails, it didn’t make sense to lay out the page in WordPress’ page sec­tion. Instead I cre­ated a page tem­plate called gallery.php, which includes all of the images and code for the page.

I also copied all of the full size and thumb­nail images into my tem­plate image folder. This way the links to the images are no longer being stored in my database.

Conclusion

After all of these changes my web­site does seem to be a little bit faster. These types of exer­cises are good prac­tice for any web designer/developer. Having a slow web host is no excuse for not doing what you can on your end to make the site faster.

As always, any tips or improve­ments from more expe­ri­enced devel­op­ers in this area are greatly appreciated.

  1. You get what you pay for, right?