How to load local script files as fallback in cases where CDN are blocked/unavailable? [duplicate]
Asked Answered
A

10

164

I’m using a CDN for the following javascript:

For each one, how can I revert to using local copy in the instance where it may be blocked/unavailable?

Aggrandize answered 10/3, 2011 at 9:52 Comment(4)
There's a solution here: #2607925Chagrin
yes i saw something similar and was wondering how to do it for the validate and unobtrusive one too.Aggrandize
Maybe duplicate but this question is easier to findPerpend
Here is your answer: https://mcmap.net/q/42267/-best-way-to-use-google-39-s-hosted-jquery-but-fall-back-to-my-hosted-library-on-google-failCirrhosis
G
260

To confirm that cdn script loaded you can check for existence any variable/function this script defines, if it is undefined - then cdn failed and you need to load local script copy.

On this principle are based solutions like that:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/libs/jquery-1.5.1.min.js">\x3C/script>')</script>

(if there is no window.jQuery property defined cdn script didn't loaded).

You may build your own solutions using this method. For instance, jquery tooltip plugin creates $.tooltip() function so we can check it with code like this:

<script>
    if (typeof $.tooltip === 'undefined') {
        document.write('<script src="js/libs/jquery.tooltip.min.js">\x3C/script>');
    }
</script>
Gan answered 3/4, 2011 at 19:14 Comment(7)
For anyone wondering why the author uses \x3c, it's because otherwise </script> would end the script prematurely.Rainey
<\/script> works fine, too.Carabin
why not if ($.tooltip === undefined)?Taken
It's also valid, there are a lot of ways to check existence. I like typeof checks they are bulletproofGan
this works but I don't think using document.write() is the right way to do it!Civil
The usage of document.write is not recommended. The network request of a document.write script MAY be blocked by the browser: developers.google.com/web/updates/2016/08/… & chromestatus.com/feature/5718547946799104Tomfool
@EMMERICH is the only one that has it right. This answer will fail in ChromeDoner
Y
16

I would have looked into a plugin like yepnopejs

yepnope([{
  load: 'http:/­/ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js',
  complete: function () {
    if (!window.jQuery) {
      yepnope('local/jquery.min.js');
    }
  }
}]);

Takes an array of object to check for, check the documentation at the site

Yatzeck answered 2/4, 2011 at 9:32 Comment(6)
Nice solution. From the documentation it seems like you still need to test for an object: yepnope([{ test : /* boolean(ish), .... So it seems @Aggrandize that you'll need to figure out an object to test for.Warmhearted
But is the completeevent fired if load fails? Looks awkward :-)Diocese
@Diocese - excellent question. From the docs it looks like you can use callback: function (url, result, key) {...} which fires on load or timeout. The default timeout can be overridden. I can't say I've tried it but looks like it might be worth the awkwardness ;)Warmhearted
On the other hand, it's complete (like in "complete failure"), not success ;-)Diocese
Complete fires regardless of success or failure, after all files are loaded/not loaded. Callback fires after loading (or not loading) a single file.Colombi
2015 note: yepnope is deprecated :(Nutrient
M
6
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script>
<script>!window.jQuery && document.write(unescape('%3Cscript src="js/libs/jquery-1.4.2.js"%3E%3C/script%3E'))</script>

Taken from HTML5 Boilerplate.

Montenegro answered 6/4, 2011 at 6:29 Comment(0)
C
5

I use http://fallback.io/

  fallback.load({
        // Include your stylesheets, this can be an array of stylesheets or a string!
        page_css: 'index.css',

        // JavaScript library. THE KEY MUST BE THE LIBARIES WINDOW VARIABLE!
        JSON: '//cdnjs.cloudflare.com/ajax/libs/json2/20121008/json2.min.js',

        // Here goes a failover example. The first will fail, therefore Fallback JS will load the second!
        jQuery: [
            '//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.FAIL_ON_PURPOSE.min.js',
            '//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js',
            '//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js'
        ],   .......
Composure answered 31/3, 2014 at 9:29 Comment(0)
C
4

first thing - shouldn't you include them in different order?

something like this should work:

<script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.7/jquery.validate.min.js"></script>
<script src="http://ajax.aspnetcdn.com/ajax/mvc/3.0/jquery.validate.unobtrusive.min.js"></script>
<script>jQuery.fn.validate || document.write('<script src="js/jquery.validate.min.js">\x3C/script><script src="js/jquery.validate.unobtrusive.min.js">\x3C/script>'</script>

what I'm doing here is simply checking if the first plugin (jQ validate) has been loaded. by checking for a static validate function on jQuery.fn object. I can't check the second script same way, because it's not adding anything anywhere, just proxying existing methods, so it's easier to assume that if the first one works, the second one will work too - after all, they are provided by the same CDN.

Celia answered 27/3, 2011 at 21:57 Comment(1)
You can test for unobtrusive with "window.jQuery.validator.unobtrusive". I found the test here: house9.blogspot.com/2011/03/…Carrel
O
2

You need to know, how you can make sure that a lib was loaded successfully. For instance:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.js"></script>
<script>window.jQuery || document.write('<script src="js/jquery.min.js">\x3C/script>'</script>

So this trys to load jQuery (1.5.1) from the google CDN. Since <script> tags do block the overall render & execution process (if not explicitly told different), we can check right after that if the jQuery object is found within window. If not, just fallback by writing another <script> tag into the document, referencing a local copy.

Ossify answered 10/3, 2011 at 9:59 Comment(1)
how do i do it for the validate and unobtrusive one?Aggrandize
L
2

The following solution passes validation for both HTML5, XHTML 1.0 Transitional and other HTML flavors. Place the following after each of your external JQuery call. Be sure to replace jquery.min.js with the path to your local copy of the JQuery script.

<script type="application/javascript">window.jQuery || 
document.write(unescape('%3Cscript src="jquery.min.js"%3E%3C/script%3E'))</script>

If you don't use unescape, you'll have errors when validating with http://validator.w3.org since "%" is not allowed in an attribute specification list.

The HTML5 Boilerplate example also has validation errors when used with older HTML:

  1. required attribute "type" not specified
  2. character "&" is the first character of a delimiter but occurred as data

You'll be fine with the HTML5 Boilerplate solution if you are developing only for HTML5 and future HTML flavors, but since you may find yourself inserting portions of your code into legacy HTML, play it safe with this one-size-fits-all approach.

You'll need to specify a different function for each externally hosted script. For instance, the JQuery Tooltip plugin creates the $.tooltip() function, so you can check it with the following:

<script type="application/javascript">typeof ($.tooltip()) !== 'undefined' || 
document.write(unescape('%3Cscript src="jquery.tooltip.min.js"%3E%3C/script%3E'))</script>
Ludwigg answered 12/7, 2012 at 20:18 Comment(0)
M
1

I answered a similar questions at jquery ui - how to use google CDN

You can make the call using

<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/themes/base/jquery-ui.css" type="text/css" media="all" /> 
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.5.min.js" type="text/javascript"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/jquery-ui.min.js" type="text/javascript"></script>

You can also link to other Ui themes by changes the name of the theme. In This case change the name base to any other theme name /base/jquery-ui.css to any other theme.

<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/themes/base/jquery-ui.css" type="text/css" media="all" />

Check out the jQuery UI Blog for a link of all CDN links http://blog.jqueryui.com/

If you want to revert back to your host in case Google failed, you can do

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
<script type="text/javascript">
if (typeof jQuery == 'undefined')
{
    document.write(unescape("%3Cscript src='/jquery.js' type='text/javascript'%3E%3C/script%3E"));
}
</script>
Mandrill answered 8/4, 2011 at 6:51 Comment(1)
This doesn't fallback-load the CSS, though...Doublejointed
E
0
<script src="http://ajax.aspnetcdn.com/ajax/mvc/3.0/jquery.validate.unobtrusive.min.js" type="text/javascript"></script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.7/jquery.validate.min.js" type="text/javascript"></script>   
<script type="text/javascript">
if(typeof jQval == 'undefined')
{
    document.write(unescape("%3Cscript src='/Scripts/jquery.validate.unobtrusive.min.js' type='text/javascript'%3E%3C/script%3E"));
    document.write(unescape("%3Cscript src='/Scripts/jquery.validate.min.js' type='text/javascript'%3E%3C/script%3E"));
}
</script>

Taken from this article

Epirogeny answered 27/3, 2011 at 21:42 Comment(1)
Why escape and unescape it?Message
S
0

Best to do all this script loading with your own Javascript code.

First try to load the CDN file by inserting a new SCRIPT element into the DOM. Then check that it has loaded by looking for an object that it defines. If the object does not appear, then insert another SCRIPT element to load the local copy. Probably best to clean up the DOM and remove SCRIPTs which failed to load as well.

Don't forget to account for timing issues, i.e. load is not instant.

Supplicatory answered 9/4, 2011 at 20:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.