Hack YSlow to ignore CDNs, a HOWTO, part deux
February 20, 2008
So in my first installment, I showed you how to configure Firefox to "grade on a curve," pointing CDNs at "100" when you are not using a CDN, or have no short/long term needs for a CDN.
The configuration method is by far the easiest.
But what if you want to do as Steve Souder points out in the Rule 2 discussion, "ignore or weight CDNs differently"? This will mean you will have to invasively hack YSlow. This option may not be for the faint at heart. Additionally, you have to consider that weighting or ignoring CDNs in YSlow will negatively affect your score. And in the end you might just want to wait for Steve's YSlow update.
How YSlow Works
YSlow uses a weighted averaging scheme. I won't explain what this means, but suffice to say your YSlow score is not averaged against 13 rules, but an effective 64 rules. You can find the default weights in yslowcontext.js.
this.lintweights = { "NumComps" : 8,
"CDN" : 6,
"Expires" : 10,
"Gzip" : 8,
"CssAtTop" : 4,
"JsAtBottom" : 4,
"Expression" : 3,
"ExternalFiles" : 4,
"Domains" : 3,
"Obfuscate" : 4,
"Redirects" : 4,
"JsTwice" : 4,
"ETags" : 2
};
By example, CDNs are weighted "6". This means that a score of 0 is 0, or a score of 100 is 600. So setting a weight of 0 will goose egg your average, and so on. Removing CDNs from the equation changes the number of items, weighted of course, to average against.
Enough math. Now, what to do, what to do?
Method 1, Simple Weighted Average
Finding the yslowcontext.js file will be an exercise for Windows users, but simple enough. The file is located on a Mac is in the following location:
/Users/{user.name}/Library/Application Support/Firefox/Profiles/{profile.name}/extensions/yslow@yahoo-inc.com/chrome/content/yslow/yslowcontext.js
The location is nearly the same on Windows and Linux, just substitute your "Documents and Settings/Application Data" folder and user home as appropriate.
Locate the lintweights object and change the property for CDN to "0". Save, restart Firefox. CDNs are effectively ignored.
But like my first post, the noise is still present about not having a CDN, etc. What about actually changing the behavior of YSlow to truly ignore the CDN rule, removing the noise? It can be done, and is more invasive. Caution, all ye that read further...
Method 2, Alter YSlow Messaging and Averaging
Instead of changing the weighted average, we can add 1) a Firefox configuration and 2) a conditional branch in the lint.js file where YSlow builds the presentation in Firebug. Here we go...
Step 1 is to create a new boolean preference in Firefox. This is not unlike the earlier post:
- Type "about:config" in the location bar
- Right-click in the window and select "New > Boolean"
- Create the preference: name: extensions.firebug.yslow.ignoreCDN, value: true.
- Restart Firefox
Step 2 is to hack the lint.js file to do actually do the "ignoring" part, and present a friendly message when using it.
Find the lint.js file, it is in the same location as yslowcontext.js and back it up.
Around line 80, you will find the function that builds the CDN report. Simple study will show that it loops over the components of the page reported to it from Firebug, appropriately adjusts your score and moves on.
We are now going to wrap this behavior in an if branch based on our new Firefox preference. At line 86, some context provided, insert the following:
...
hLint["rulehref"] = "http://developer.yahoo.com/performance/rules.html#cdn";
if( YSLOW.getPref("yslow.ignoreCDN", false) ) {
// you will be adding some code here later
} else {
var compObj = {};
...
Whew... what is happening here? Basically, we are telling YSlow that if you don't a preference for ignoring CDNs, assume it is false and execute the else statement. Which is where the original code is now blocked at line 88. Let's make sure we don't break this function and close the else block at line 140:
... FirebugContext.yslowContext["lintscores"]["CDN"] = iScore; } return hLint;
Now, it is time to tell YSlow how we want it to behave when ignoring CDNs. We are going to borrow liberally from Rule 8 and it's code. Insert the following, copy and paste if you desire, the following at line 87 (shown above as "blank"):
hLint["nonwarnings"] = "Only consider this if your property is under heavy load, for example from file sharing and streaming media; may not be applicable to small and medium properties."; hLint["score"] = "n/a"; // This rule should require manual evaluation. Don't score it automatically. // FirebugContext.yslowContext["lintscores"]["CDN"] = iScore;
Note, line breaks are for readability, see line numbers. Lines reflect the new code inserted.
Save and restart Firefox.
Have fun
Finally, one might wish to clean up the code and indent the new branch, for readability. Or not. It works as is. Comment on your experience or make suggestions.