Using CDN Hosted jQuery with a Local Fall-back Copy
Update: See Scott Hanselman's post for more info: CDNs fail, but your scripts don't have to - fallback from CDN to local jQuery
There are a lot of good reasons to stop hosting your own local copies of common Javascript includes like jQuery and ASP.NET AJAX. Dave Ward summed up the top three reasons:
Decreased Latency
A CDN — short for Content Delivery Network — distributes your static content across servers in various, diverse physical locations. When a user’s browser resolves the URL for these files, their download will automatically target the closest available server in the network…
Increased parallelism
To avoid needlessly overloading servers, browsers limit the number of connections that can be made simultaneously. Depending on which browser, this limit may be as low as two connections per hostname. Using the Google AJAX Libraries CDN eliminates one request to your site, allowing more of your local content to downloaded in parallel.
Better caching
Potentially the greatest (yet least mentioned) benefit of using the Google AJAX Libraries CDN is that your users may not need to download jQuery at all. No matter how aggressive your caching, if you’re hosting jQuery locally then your users must download it at least once. […] When a browser sees multiple subsequent requests for the same Google hosted version of jQuery, it understands that these requests are for the same file. Not only will Google’s servers return a 304 “Not Modified” response if the file is requested again, but also instructs the browser to cache the file for up to one year. This means that even if someone visits hundreds of sites using the same Google hosted version of jQuery, they will only have to download it once.
Dave refers to the Google AJAX CDN because it was the only game in town at the time of his post, but since then Microsoft has begun hosting not only jQuery, but also the ASP.NET AJAX libraries.
When you consider that this is offered as a free service, why wouldn’t you be using it?
What about outages?
There’s one potential downside to outsourcing anything: potential outages. You might be tempted to brush that aside with “Hey, it’s run on a world-class CDN...” but it can and has happened. If your depends on jQuery, any CDN outages are essentially another outage for your site.
The outage scenario is mitigated by the fact that browsers should be using cached copies rather than contacting the CDN in most cases, but that doesn’t always work out in practice.
The other outage scenario – no (or unreliable) internet connection
The most common “outage” scenario for a CDN is when the browser has no internet access at all. There are two common cases developers run into this:
- Developing offline – Requiring a constant internet connection to develop your app can be really frustrating. It means you can’t develop when you’re mobile or travelling, and even when you’ve got a connection it can slow down your development feedback cycle.
- Demonstration and sample code – If you’re presenting an app or sharing demo code, depending on CDN access is an invitation to the demo gods to rain doom on your head.
The simple solution: Use a fallback when the CDN’s unreachable
Here’s a general pattern for AJAX includes with a fallback: include the CDN reference, test for a key object, and if it’s undefined you can write out a reference to a copy that you’re hosting. Here’s how that looks when using the Microsoft hosted jQuery libraries with an ASP.NET MVC application:
<script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.min.js"></script> <script type="text/javascript"> if (typeof jQuery == 'undefined') { document.write(unescape("%3Cscript src='/Scripts/jquery-1.3.2.min.js' type='text/javascript'%3E%3C/script%3E")); } </script>
And here’s how I’d set that up with ASP.NET AJAX library references in an ASP.NET MVC app:
<script src="http://ajax.microsoft.com/ajax/3.5/MicrosoftAjax.js" type="text/javascript"></script> <script src="http://ajax.microsoft.com/ajax/mvc/1.0/MicrosoftMvcAjax.js" type="text/javascript"></script> <script type="text/javascript"> if (typeof Sys == 'undefined') { document.write(unescape("%3Cscript src='/Scripts/MicrosoftAjax.js' type='text/javascript'%3E%3C/script%3E")); document.write(unescape("%3Cscript src='/Scripts/MicrosoftMvcAjax.js' type='text/javascript'%3E%3C/script%3E")); } </script>
Correctly handling virtual roots on ASP.NET
Rick Anderson reminded me that the above doesn't work well in a virtual root - you need to remove the leading / in the script references. A better approach in ASP.NET / Razor is to use Url.Content, which handles that automatically:
<script type="text/javascript"> if (typeof jQuery == 'undefined') { var e = document.createElement('script'); e.src = '@Url.Content("~/Scripts/jquery-1.7.1.js")'; e.type='text/javascript'; document.getElementsByTagName("head")[0].appendChild(e); } </script>
But will it blend?
It carries the “works on my machine” guarantee. One easy way to test is to mangle the CDN references – change “ajax.microsoft.com” to “kissypoo.microsoft.com”. You’ll get a Javascript error due to the bad reference, but the fall-back reference will be loaded. You can verify that by debugging the code.
This also carries the “Lots of Upvotes On StackOverflow” guarantee, and you can see from the comments on Dave’s post that he’s looked into it, too.