

Fallback from CDN to local jQuery - shawndumas
http://www.hanselman.com/blog/CDNsFailButYourScriptsDontHaveToFallbackFromCDNToLocalJQuery.aspx

======
romaniv
I still find the idea of CDNS repugnant. No matter how you slice it, you rely
on an external resource for important parts of your application. "What it it
goes down?" is one question. But you also should be asking yourself about what
will happen if it gets hacked. There are also user privacy issues, which get
completely overlooked in the chase for shaving off several milliseconds off
request time.

A much better architecture would be to serve JavaScript from your server by
default, but allow for distributed content-based caching. For example, your
script tag could look like this

<script src="some.js" hash="ha3ee938h8eh38a9h49ha094h" />

The hash would be calculated based on the content of the file. The browser
then could fetch it from whatever source it wants. Users could cache stuff
locally (across websites), without needing to dial into a CDN every time. You
could even use a torrent-like network for distributed delivery of popular
script libraries.

~~~
olegp
It's not just a few milliseconds though. For example at <https://starthq.com>,
we are based in Finland, but host on Amazon in US East. A round trip to the US
is 200ms+ whereas with CloudFront it's 8ms. Before we used a CDN our page took
a few seconds to load - now it takes around 200ms.

I should also mention that all this happens only on first load. We embed etags
in the URLs and use far off cache control expires dates, so subsequent page
loads get the JS and CSS from the browser's cache.

~~~
bsimpson
I think there's confusion here about the use of the term CDN. There are
_public_ CDNs, like Google AJAX APIs, that allow a shared copy of an open-
source library to be downloaded from a known-good location. This enables users
to reuse the same copy their browser has already cached across multiple pages,
but like romaniv and the OP have pointed out, you are then trusting Google to
be good stewards of that resource.

Conversely, you control what shows up on your own _private_ CDN, like
CloudFront. Sure, there may be downside outside of your control, but nobody is
going to be able to alter the resources there without your permission.

~~~
jmillikin

      > Conversely, you control what shows up on your own
      > private CDN, like CloudFront. Sure, there may be
      > downside outside of your control, but nobody is going
      > to be able to alter the resources there without your
      > permission.
    

Well, CloudFront could, since they control the machines that your users are
connecting to.

~~~
pyre
One could say the same of any host.

~~~
jmillikin
That's the point; it's silly to say that <https://some-
cdn.com/jquery-1.9.1.min.js> is inherently less secure than <https://my-
cloudfront-proxied-site.com/jquery-1.9.1.min.js>

~~~
pyre
Well, it also depends on your level of trust for Google vs. CloudFront.

------
wyuenho
This only works if the CDN actually returns 4xx or 5xx codes. This still won't
work if the CDN is getting DDOS'ed, as in taking forever to return anything.

~~~
gavinpc
Along the same lines, Chrome (maybe just webkit generally) does not fire
DOMContentLoaded until external script requests have resolved _or timed out_ ,
even if they are _async_.

Also, I don't understand why people feel so strongly about reposting this
"document.write" method everywhere, which I found in some cases made my page
disappear at load time. You can do the same thing using regular DOM methods,
and you get more control over the process.

~~~
youngtaff
I believe the blocking of DCL is expected behaviour for scripts with async
attribute [http://www.whatwg.org/specs/web-apps/current-
work/multipage/...](http://www.whatwg.org/specs/web-apps/current-
work/multipage/scripting-1.html#attr-script-async)

If you insert the script using a script it's execution is delayed until after
DCL

------
isalmon
I personally decided to use a local file after all.

Pros:

\+ I can cache it for a very long time, so all my returning visitors don't
have re-download it. I was very surprised to see that CDN's jquery had a very
short 'Expire' headers

\+ If my server is up and users can open a web page - there's a very high
chance that the .js file will load as well.

\+ I can combine different jquery libraries/plugins into one file, so my page
can load MUCH faster

Cons:

\- It might load a little more slowly, because it's not on CDN.

Am I missing something?

~~~
Encosia
The Google CDN serves jQuery with a 365 day max-age as long as you reference a
specific version (which you should be doing anyway). It only uses the shorter
cache expiration, necessarily, if you want a "latest version" reference. More
info here: [http://encosia.com/the-crucial-0-in-google-cdn-references-
to...](http://encosia.com/the-crucial-0-in-google-cdn-references-to-
jquery-1-x-0/)

------
MatthewPhillips
It saddens me that ES6 modules don't have fallbacks built in. You do:

    
    
        import 'http://developer.yahoo.com/modules/yui3.js' as YUI;
    

wish it was:

    
    
        import ['http://developer.yahoo.com/modules/yui3.js', '/libs/yui3'] as YUI;

~~~
SoftwareMaven
I think the notion of "fallbacks" (and the sibling comment's "timeouts") are
extremely specific to the web. However, there is some prior art on this
subject in the python world:

    
    
      try:
          import simplejson as json
      except ImportError:
          import json
    

So it might be worth contacting the committee and expressing that.

------
sleepyhead
Fallback to a CDN has been blogged about for a while, don't understand why it
is being upvoted now. However, do note the issues presented by Steve Souders
though: [http://www.stevesouders.com/blog/2013/03/18/http-archive-
jqu...](http://www.stevesouders.com/blog/2013/03/18/http-archive-jquery/)

One thing is that only about 1% have the specified version you use on your
site.

------
mrharrison
If you guys take a look at html5 boilerplate <http://html5boilerplate.com/> .
It has redundancy built in, so if the cdn fails, it will load your local copy.

~~~
mrharrison
Also, you shouldn't be serving your content from a cdn anyway. All of your js
files should be compressed into one file, browser cached, and gzipped.

~~~
dangrossman
Making the file smaller doesn't reduce latency. The point of a CDN is local
distribution, not just load balancing. You also get to share a cache with
other sites; if you point to jQuery on Google's CDN, and the visitor has been
to any other site using that CDN, they already have the file cached.

~~~
nilliams
>> Making the file smaller doesn't reduce latency

No, but I think the parent was making the case for combining everything into a
single file (jQuery + app) which has benefits in reducing number of HTTP
requests, especially important on mobile for example.

>> The point of a CDN is local distribution, not just load balancing.

Personally, I build web-apps for UK customers, and host in the UK, so this is
a non-issue. I suspect the same is true for a lot of people building complex
web-apps (i.e. apps complex enough that you should care about your build
process).

>> You also get to share a cache with other sites; if you point to jQuery on
Google's CDN, and the visitor has been to any other site using that CDN, they
already have the file cached.

Not really true, they have to have hit another site that has uses that _exact
version of jQuery_ in order to have it cached. There was a study done recently
that illustrated this was very unlikely. I wish I could link to it, but all I
can tell you is Alex Sexton referenced it on the Shoptalk podcast [1].

Edit: Another commenter has now referenced the survey in question [2].

[1] <http://shoptalkshow.com/episodes/061-with-alex-sexton/>

[2] [http://www.stevesouders.com/blog/2013/03/18/http-archive-
jqu...](http://www.stevesouders.com/blog/2013/03/18/http-archive-jquery/)

------
3825
Will we see (a few very) popular frameworks like jQuery built into web
browsers with the server just declaring what version to use? (I have a feeling
that, although I have good intentions, this is a bad idea.) Thoughts?

~~~
emehrkay
I hope not. Especially at the pace that these things change (just about every
jQuery release is followed up by a point update a day later)

~~~
3825
I'd like to believe Chrome* users are usually up to date on version numbers.
We could update the library cache on a different schedule from browser
updates. Finally, we could fall back to a CDN (with further fall back to your
own server?) if the server requests jQuery 2.0.1 and the browser says sorry,
best I can do is 2.0.0.

My fear was more on the server-side. Can we accomplish this without further
butchering the head from the standard? I can't see all browsers adopting this
or it becoming a standard without a major sponsor. And like someone else
mentioned, we can get about the same benefits from aggressive caching. I agree
for the most part.

Don't get me wrong. I love Google. I love what they do to make the web faster
with their hosted libraries[1]. Correct me if I am wrong but caching the
libraries from Google only helps if the the server specifies they want that
particular file from Google (I'd imagine it would be a gaping security hole
any other way). My thought is whether it is possible to just declare something
like 1.9.1.min.jQuery.com and have the browser just recognize it and say "Oh
yes I have that. No need for a server round trip. You're welcome." or "No, I
don't understand what you're talking about. Give me an address so I can fetch
it."

Is it even worth it? jQuery 1.9.1 minified is ~90 kB, so we're probably just
trying to shave off tens of milliseconds at the most. I bet we all have fruits
hanging lower than this to worry about it. Another thing is that it will
probably have to be a vendor-specific meta tag (as I don't see everyone
getting aboard this, if anyone) in the header which I don't know is a good
thing.

[1] <https://developers.google.com/speed/libraries/>

*I believe Mozilla Firefox has also started silent updates. It'd be nice to see how quickly users update when a new build gets pushed out.

~~~
maggit
You could do something like:

    
    
      <script
        src="my-copy-of-jquery.1.9.2.js.min"
        cannonical-uri="https://jquery.com/jquery.1.9.2.js.min" 
        hash="SHA1-blablabla"
      ></script>
    

With this setup:

1\. Old browsers could work as before

2\. New browsers could download your resource and cache it with the
cannonical-uri and calculated (not declared!) hash as cache key (no dependency
on third party CDNs)

3\. New browsers could serve this resource from cache if it had downloaded it
before with matching cannonical-uri AND hash, disregarding src and host

The hash would make sure that the jquery the user downloaded from whereever
would indeed be the same jquery you are serving up.

\----

Going back to your original idea, browsers could absolutely come with
prepopulated caches for such resources, but they might as well fill these
caches on demand.

The important thing in both cases would be to allow shared caching between
sites without forcing everybody to agree on which CDN is the most pleasing.
Notice that the cannonical-uri is only a name, it is not supposed to be
dereferenced.

~~~
3825
That looks beautiful. So the hash basically says "I trust this source"?

>>The important thing in both cases would be to allow shared caching between
sites without forcing everybody to agree on which CDN is the most pleasing.
Notice that the cannonical-uri is only a name, it is not supposed to be
dereferenced.

Yes, you put it much better than I could have. Thank you!

~~~
gertef
No, the hash is how you verify that the source (or the transmission) hasn't
corrupted the content.

~~~
3825
It is a fingerprint of the file then, right?

------
jrochkind1
The document.write method makes it impossible to do async script loading, that
you ordinarily could do here to improve perceived page load time. No?

I mean, for instance, you couldn't load that FIRST CDN jquery as async,
because you need the browser to block on it so your NEXT script tag (which
also can't be loaded async, naturally, cause it has a document.write in it)
can check to see if it was loaded.

~~~
xkcdfanboy
Yes, that first method is hideous. Async is a necessary speedup and the `if
(jQuery) ` slaughters that optimization.

------
esalman
This is built into Bootstrap.

~~~
mac1175
I have seen this in the HTML5 Boilerplate code in line 27-28
[https://github.com/h5bp/html5-boilerplate/blob/master/index....](https://github.com/h5bp/html5-boilerplate/blob/master/index.html)

~~~
wubbfindel
FYI, You can link directly to lines in github:
[https://github.com/h5bp/html5-boilerplate/blob/master/index....](https://github.com/h5bp/html5-boilerplate/blob/master/index.html#L27)

~~~
waffle_ss
Also, I would avoid linking to 'master' as it's a moving target (in the future
such a link could point to completely different code or even a file that
doesn't exist). I try to link to the actual commit that master is pointing to
at the time:
[https://github.com/h5bp/html5-boilerplate/blob/7a22a33d4041c...](https://github.com/h5bp/html5-boilerplate/blob/7a22a33d4041c479d0962499e853501073811887/index.html#L27)

~~~
oneeyedpigeon
You can also link to line ranges, which is relevant in this case:
[https://github.com/h5bp/html5-boilerplate/blob/7a22a33d4041c...](https://github.com/h5bp/html5-boilerplate/blob/7a22a33d4041c479d0962499e853501073811887/index.html#L27,L28)

~~~
mac1175
Thanks! This is much helpful.

------
kmfrk
The main reason you should do this is not so much as a CDN fall-back, but to
prevent users from downloading redundant files retrieved from other sites.

Also remember to always use the https URL for the assets, whenever able.

~~~
imjared
Is there a reason to use https over a protocol-relative url? My go-to is
<script
src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>

~~~
pyre
Some older versions of IE don't like protocol-relative, IIRC. Depends on your
target platform, and customer-base.

~~~
Encosia
I've tested the protocol-relative URL in every version of IE that was
available on Browsershots about a year ago (which went back even further than
IE6, IIRC). None of them had trouble with it.

~~~
pyre
I remember suggesting it to someone else at my previous employer and there
were issues. It may have been Outlook[1] though. I can't recall off-hand.

[1] [http://stackoverflow.com/questions/4303633/preventing-
secure...](http://stackoverflow.com/questions/4303633/preventing-secure-
insecure-errors-by-using-protocol-relative-urls-for-image-sour)

------
jjoergensen
Simple stuff should be simple

------
gwgarry
I have always thought that all the stuff in common CDNs should be available in
local storage by default. Common stuff like jQuery and the like. Firefox
should have this as a feature where it downloads those scripts once and stores
them in local storage. That way you're not leaking privacy everywhere you go
to Google et. al.

~~~
addandsubtract
That would be ideal, but currently local storage doesn't work across domains.

