FortAwesome / Font-Awesome

The iconic SVG, font, and CSS toolkit
https://fontawesome.com
Other
74.28k stars 12.2k forks source link

Feature request: Local fallback on Font Awesome Kit CDN/SRI failure #15159

Open StuartMorrisAU opened 5 years ago

StuartMorrisAU commented 5 years ago

Is your feature request related to a problem? Please describe. If the CDN resource (Font Awesome CDN, or other such as cdnjs, jsDelivr, etc) cannot be loaded for any reason, or the SRI hash check fails for any reason, Font Awesome won't be loaded.

Describe the solution you'd like There should be a way to perform a check for such a failure so that if it happens, it can fallback to a local copy of the resource. Is there a way to do this with Font Awesome? I use a FA Kit, but it could just as easily be for a third-party CDN-loaded resource.

Describe alternatives you've considered N/A

Additional context For example, this can be done using jQuery as follows:

<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo= sha384-vk5WoKIaW/vJyUAd9n/wmopsmNhiy+L2Z+SBxGYnUkunIxVxAv/UtMOhba/xskxh sha512-bnIvzh6FU75ZKxp0GXLH9bewza/OIw6dLVh9ICg0gogclmYGguQJWl8U30WpbsGTqbIiAwxTsbe76DErLq5EDQ==" crossorigin="anonymous">
<script>(window.jQuery) || document.write('<script src="/scripts/jquery.min.js"><\/script>');</script>

Feature request checklist

joshg2k commented 4 years ago

+1 to show my support for this request.

garyapps commented 4 years ago

+1 from me as well.

This is a more important issue than you may realize. We do not use the CDN because there is no fallback mechanism, and half the buttons on our site are font-awesome icons, so the site would be unusable if the CDN failed. We need a way to detect failure so that we can load a local version of the .js file.

This is probably the easiest feature request you will ever receive. I believe all you need to do is put a global variable in your js file, maybe name it something like iAmAwesome, and we will then be able to implement a fallback using

<script src="https://kit.fontawesome.com/xyz.js" crossorigin="anonymous"></script>
<script>
    (window.iAmAwesome) || document.write('<script src="/local/fontawesome/all.min.js"><\/script>');
</script>
tagliala commented 4 years ago

Hi,

the kit should expose FontAwesome to the window object, could you please check?

edit: FontAwesomeKitConfig. Then it will load the actual framework, but it will be another call that may fail

garyapps commented 4 years ago

Hi @tagliala ,

Yes, I see both window.FontAwesome and also window.FontAwesomeConfig.

In the fallback logic should I check for just one of them or both of them?

(I did not understand what you mean by "Then it will load the actual framework, but it will be another call that may fail")

robmadole commented 4 years ago

Using the SVG with JavaScript version of Font Awesome will set a public (as in we guarantee we will not change this) attribute on window. So using window.FontAwesome can accomplish what is being done in the example.

tagliala commented 4 years ago

(I did not understand what you mean by "Then it will load the actual framework, but it will be another call that may fail")

Hi,

I mean that the first request will just load the kit configuration, that will make a second (async) request to load the SVG framework (free.min.js) or to the CSS framework.

Demo: https://jsfiddle.net/tagliala/0r5L9dfz/45/

Check the network tab: image

In other words, this approach

<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo= sha384-vk5WoKIaW/vJyUAd9n/wmopsmNhiy+L2Z+SBxGYnUkunIxVxAv/UtMOhba/xskxh sha512-bnIvzh6FU75ZKxp0GXLH9bewza/OIw6dLVh9ICg0gogclmYGguQJWl8U30WpbsGTqbIiAwxTsbe76DErLq5EDQ==" crossorigin="anonymous">
<script>(window.jQuery) || document.write('<script src="/scripts/jquery.min.js"><\/script>');</script>

does not guarantee that the icons are available, you should check the document after it is has been completely loaded.

garyapps commented 4 years ago

I just realized that when using the pro version of the font awesome kit (paid account) both the window.FontAwesome and window.FontAwesomeConfig variables are present. However when using the free version of the font awesome kit only window.FontAwesomeConfig is present whereas window.FontAwesome is not. Can you confirm this behavior?

I ask because I was using window.FontAwesome as a test to trigger fallback code, but am now wondering if maybe I should be using window.FontAwesomeConfig instead.

Edit: Never mind. I realized that the free kit was by default set to use Web Font technology rather than SVG. Once I changed it to SVG the window.FontAwesome variable became available. So window.FontAwesome is only available in the SVG version. Not sure why this happens, but leaving this comment here in case someone else runs into the same issue.

garyapps commented 4 years ago

@robmadole and @tagliala - Unfortunately the approach did not work. Although window.FontAwesome is present (when using the SVG technology), the variable is not immediately present. I think the kit url loads the script in a deferred manner. So when the fallback test is encountered, window.FontAwesome is not yet available, and the test fails.

Here is what my code looks like:

<script src="https://kit.fontawesome.com/xxxxxxxxxxx.js" crossorigin="anonymous"></script>
<script>
    (window.FontAwesome) || document.write('<script defer src="/fontawesome/js/all.js"><\/script>');
</script>

At the time of code execution, window.FontAwesome is undefined. so the local source gets used every time. This means there is no point in using the kit url since the local file will always get used.

Do you have any suggestions on how to resolve this?

tagliala commented 4 years ago

I think the kit url loads the script in a deferred manner.

Confirm

Please refer to https://github.com/FortAwesome/Font-Awesome/issues/15159#issuecomment-630308600

garyapps commented 4 years ago

Ok, so then the only way to do the fallback test is to run it after the entire page (including scripts) have finished loading (aka after window.onload).

Here is my new code that seems to be working, in case anyone else is interested -

<script src="https://kit.fontawesome.com/xxxxxxxxxxx.js" crossorigin="anonymous"></script>
<script>
    window.onload = function () {
        if (!window.FontAwesome) {
            var scriptElement=document.createElement('script');
            scriptElement.type = 'text/javascript';
            scriptElement.src = "/fontawesome/js/all.js";
            document.body.appendChild(scriptElement);
        }
    }
</script>
tagliala commented 4 years ago

@garyapps thanks, I've updated my fiddle to include your approach