Load JavaScript libraries from CDN with local fallback using yepnope.js
This is a demo example showing how to load JavaScript from CDN with a given timeout. If the script has not been loaded in the given time limit, the a local script is loaded.
Goal
Lets say we need D3 library. We hope that by loading the library from CDN url (http://d3js.org/d3.v3.min.js) we reuse the d3 library the user might have in his browser cache. This is the good recommended practice, but sometimes it fails. For example, some of our clients in Asia experience CDN timeouts for common libraries: jQuery, angular.
I would like to provide a fallback way to load the library from our local vendor folder included with the website. This demo shows how to do this.
Setup
I am using yepnope.js to load scripts on demand.
This loader script is very small, allows loading JavaScript and CSS
and loads scripts in order depending on the condition (the test
property).
Here is an example:
1 | // load D3 library if it has not been loaded already |
If any of the libraries were already loaded in the page, the load is skipped using
the test condition test: window.d3
. The initial load script is loaded form http://d3js.org
,
once it completes, we check for window.d3
again, and if it has not been setup,
we try loading the local script included in the vendor
folder.
Loading several libraries
yepnope can load multiple libraries in parallel, but I found that the result is not ordered if any library is loaded via secondary fallback download. To load two scripts, just specify multiple test objects in the given array
1 | yepnope([{ |
The only change required to make AngularJs work is switch from immediate ng-app="module name" code to bootstrapping inside a separate function, for example called initApp. An example:
1 | function initApp() { |
When using delayed bootstrapping like this, you don't need to declare ng-app
attribute.
To make sure our application is only initialized when all libraries are available, I check the conditions on every library download. If all pass, the application can be bootstrapped.
1 | function onAngularLoaded() { |
I added run once guard inside the initApp function to prevent multiple AngularJs bootstrapping (due to any timing issues or bugs in the loader script).
1 | (function () { |
Time limits
By default yepnope gives up on loading a script after 10 seconds.
You can specify different timeout using timeout=<ms>!<url>
syntax. For example,
lets try loading d3 from a CDN with 1 second timeout
1 | yepnope([{ |
If the DNS lookup + library download from d3js.org does not succeed in less than 1000ms, local callback will start downloading a local version.
Demo
I created a simple demo with a doughnut chart that requires both D3 and Angularjs scripts. The download limit is determined randomly, the download events are written to console window. If you refresh several times you should experience successful / failed CDN events and local download fallbacks.
All code is available on github, with main logic in the index.html