January 2010 - Posts - Jon Galloway

January 2010 - Posts

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"));

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"));

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")';

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.

Tip: File / Open / URL

As web developers, we’re constantly having to work with files that are provided via URL. The simplest case is a web page source HTML, but there’s also XML config files, images, documents (PDF, PSD, DOCX, etc.). Usually we don’t think about it, because they’re linked in a web page, so we we do the right-click/save file, then open our editor and do the file/open/browse… where did I save it again… dance. If we remember to shift-right-click/copy as path trick, we think we’ve cheated the system just a bit.

It’s even worse if we just have a URL that’s not in a webpage. How many times have you fired up notepad to type a one-line HTML file with something like this: <a href=”http://domain.com/file-i-want.xml”>click me</a>? Then you open that file in a browser, right-click, save file, dum-de-dum…

There’s a better way!  (Yes, better than wget)

Last year I was working on a video site that streamed ASX files through a pretty complex Silverlight video player. ASX is one of those funny file formats that looks a lot like XML, but isn’t, and to top it off there are some funky ASX features that Silverlight doesn’t support. So I ended up having to write an ASX parser, and doing a lot of testing against our video providers every time something strange happened with our various video feeds. I was constantly copying URL’s into one-off HTML files, and eventually I just had to go looking for a better way.

It turns out that you can open URL’s directly in Visual Studio. Try it!

Open Visual Studio (any version) and hit Ctrl-O to bring up an open file dialog, then type in a URL. Here I’m using http://microsoft.com:


When I click enter, the HTML is requested and displayed:


The Fun Don’t Stop – It Works With Other Programs And Filetypes, too!

Let’s fire up good old MSPAINT and open the .NET Logo from this URL: http://www.microsoft.com/presspass/images/gallery/logos/web/ms_net_rgb_web.jpg


Now let’s try something crazy – let’s open that same URL in Inkscape, a cross platform vector graphics editor:


What’s going on?

It turns out that the Windows Open File Dialog supports URL’s, so as long as the app isn’t using a custom dialog it just magically works. The files are actually downloaded to your Temporary Internet Files folder and opened from there. Aside from the speed of opening the files directly, there’s another benefit: rather than scattering temporary files all over your documents folder or desktop, they’re in the right place to be automatically cleaned up when you clear your temporary files.

What about saving a file, rather than opening it?

Well, it’s pushing it a bit, but for simple cases, you don’t really need an app or a dummy HTML file, either. If you’ve got a file that IE won’t natively open, you can just hit Start and type: iexplore “http://domain.com/importantfiles.zip”

At that point, though, you might as well just fire up Powershell (built into Windows 7, hit Start / type Powershell / enter) and run a one-liner:

(new-object System.Net.WebClient).DownloadFile(“http://domain.com/importantfiles.zip, "localfilename.zip")

There are some other tips about downloading from the commandline on this question on SuperUser.

Why not wget / wfetch / “Crazy Eddie’s Download Powerpack” / etc.?

It’s a fair question.

Those all work, and they’re great if you’re used to them. I’ve really been trying to simplify lately, though. One of the benefits of Windows 7 is that it doesn’t need a bunch of random shareware tweaks to work well, it just works. Could I install a file downloading app? Sure, but when Windows has so much built in, there’s no real need for most simple tasks. The big benefit is that I can hop on any Windows machine and do my thing, without having to download a bunch of extra unitaskers.

Posted by Jon Galloway | 8 comment(s)
Filed under:
More Posts