Search code examples
c#asp.net-mvc-5cdnbundling-and-minificationsystem.web.optimization

How do i write a CDN fallback expression when loading a script asynchronously?


I'm setting up my jQuery bundle as follows:

var bundle = new ScriptBundle("~/bundles/jquery", "//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js");

// Path to the version of the file on your server (in case the CDN fails)
bundle.Include("~/scripts/jquery-{version}.js");

// JS expression to run, to test if CDN delivered the file or not
bundle.CdnFallbackExpression = "window.$";

bundles.Add(bundle);

In order to increase my Google PageSpeed Insights score I chose to load the script asynchronously:

@Scripts.RenderFormat(@"<script src=""{0}"" async></script>", "~/bundles/jquery")

But now, it seems to always fail the CDN fallback expression and ends up loading the script twice; once from my fallback bundle and once from the CDN when the async call finishes. I assume because when it runs the fallback test, the async call to the CDN hasn't finished.

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js" async=""></script>
<script>(window.$)||document.write('<script src="/bundles/jquery"><\/script>');</script>
<script src="/bundles/jquery"></script>

Is there a more intelligent way I can write my fallback expression?

Is there a better solution entirely?

I'd load jQuery closer to the bottom but then it'd break any inline calls that depend on it.


Solution

  • <script id="srequire" src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.jsWRONG" async="async"></script>
    <script type="text/javascript">
        function sOnerror() {
            console.log("sOnerror");
            //if (typeof window.jQuery === 'undefined') {
                var scr = document.createElement("script");
                scr.src = "/bundles/jquery";
                scr.async = true;
                document.body.appendChild(scr);
           //}
        }
        var element = document.getElementById("srequire");
        console.log("element", element);
        if (element.addEventListener) {
            //element.addEventListener("load", onsuccess, false);
            element.addEventListener("error", sOnerror, false);
        } else if (element.attachEvent) {
            //element.attachEvent("onload", onsuccess);
            element.attachEvent("onerror", sOnerror);
        } else {
            //element.onload = onsuccess;
            element.onerror = sOnerror;
        }
    </script>
    

    for u to test it I put WRONG in the js name to check that the script works I checked it on ff chrome ie opra and edge you can use requirejs but that also fail sometimes from cdn that's why I use this script happy to share hope it helps

    "If the load resulted in an error (for example a DNS error, or an HTTP 404 error) Executing the script block must just consist of firing a simple event named error at the element."

    source w3.org