Multiple files on CDN vs. one file locally

My website uses about 10 third party javascript libraries like jQuery, jQuery UI, prefixfree, a few jQuery plugins and also my own javascript code. Currently I pull the external libraries from CDNs like Google CDN and cloudflare. I was wondering what is a better approach:

  1. Pulling the external libraries from CDNs (like I do today).
  2. Combining all the files to a single js and a single css file and storing them locally.

Any opinions are welcome as long as they are explained. Thanks :)


Solution 1:

The value of a CDN lies in the likelihood of the user having already visited another site calling that same file from that CDN, and becomes increasingly valuable depending on the size of the file. The likelihood of this being the case increases with the ubiquity of the file being requested and the popularity of the CDN.

With this in mind, pulling a relatively large and popular file from a popular CDN makes absolute sense. jQuery, and, to a lesser degree, jQuery UI, fit this bill.

Meanwhile, concatenating files makes sense for smaller files which are not likely to change much — your commonly used plugins will fit this bill, but your core application-specific code probably doesn't: it might change from week to week, and if you're concatenating it with all your other files, you'd have to force the user to download everything all over again.

The HTML5 boilerplate does a pretty good job of providing a generic solution for this:

  1. Modernizr is loaded from local in the head: it's very small and differs quite a lot from instance to instance, so it doesn't make sense to source it from a CDN and it won't hurt the user too much to load it from your server. It's put in the head because CSS may be making use of it, so you want it's effects to be known before the body renders. Everything else goes at the bottom, to stop your heavier scripts blocking rendering while they load and execute.
  2. jQuery from the CDN, since almost everyone uses it and it's quite heavy. The user will probably already have this cached before they visit your site, in which case they'll load it from cache instantly.
  3. All your smaller 3rd party dependencies and code snippets that aren't likely to change much get concatenating into a plugins.js file loaded from your own server. This will get cached with a distant expiry header the first time the user visits and loaded from cache on subsequent visits.
  4. Your core code goes in main.js, with a closer expiry header to account for the fact that your application logic may change from week to week or month to month. This way when you've fixe a bug or introduced new functionality when the user visits a fortnight from now, this can get loaded fresh while all the content above can be brought in from cache.

For your other major libraries, you should look at them individually and ask yourself whether they should follow jQuery's lead, be loaded individually from your own server, or get concatenated. An example of how you might come to those decisions:

  • Angular is incredibly popular, and very large. Get it from the CDN.
  • Twitter Bootstrap is on a similar level of popularity, but you've got a relatively slim selection of its components, and if the user doesn't already have it it might not be worth getting them to download the full thing. Having said that, the way it fits into the rest of your code is pretty intrinsic, and you're not likely to be changing it without rebuilding the whole site — so you may want to keep it hosted locally but keep it's files separate from your main plugins.js. This way you can always update your plugins.js with Bootstrap extensions without forcing the user to download all of Bootstrap core.

But there's no imperative — your mileage may vary.