Programing

CDN이 실패 할 경우 로컬 스타일 시트 (스크립트 아님)로 대체하는 방법

crosscheck 2020. 8. 14. 07:15
반응형

CDN이 실패 할 경우 로컬 스타일 시트 (스크립트 아님)로 대체하는 방법


CDN의 jQuery Mobile 스타일 시트에 연결 중이며 CDN이 실패하면 스타일 시트의 로컬 버전으로 돌아가고 싶습니다. 스크립트의 경우 솔루션은 잘 알려져 있습니다.

<!-- Load jQuery and jQuery mobile with fall back to local server -->
<script src="http://code.jquery.com/jquery-1.6.3.min.js"></script>
<script type="text/javascript">
  if (typeof jQuery == 'undefined') {
    document.write(unescape("%3Cscript src='jquery-1.6.3.min.js'%3E"));
  }
</script>

스타일 시트에 대해 비슷한 작업을하고 싶습니다.

<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0b3/jquery.mobile-1.0b3.min.css" />

스크립트를로드 할 때와 마찬가지로 스크립트를 연결할 때 브라우저가 동일한 방식으로 차단되는지 여부가 확실하지 않기 때문에 비슷한 접근 방식을 얻을 수 있는지 확실하지 않습니다 (스크립트 태그에 스타일 시트를로드 한 다음 페이지에 삽입)?

그래서 내 질문은 : CDN이 실패하면 스타일 시트가 로컬로로드되는지 어떻게 확인합니까?


브라우저 간 테스트를 거치지 않았지만 이것이 작동 할 것이라고 생각합니다. 하지만 jquery를로드 한 후에야합니다. 그렇지 않으면 일반 Javascript로 다시 작성해야합니다.

<script type="text/javascript">
$.each(document.styleSheets, function(i,sheet){
  if(sheet.href=='http://code.jquery.com/mobile/1.0b3/jquery.mobile-1.0b3.min.css') {
    var rules = sheet.rules ? sheet.rules : sheet.cssRules;
    if (rules.length == 0) {
      $('<link rel="stylesheet" type="text/css" href="path/to/local/jquery.mobile-1.0b3.min.css" />').appendTo('head');
    }
 }
})
</script>

css 및 jQuery에 대해 동일한 CDN을 사용한다고 가정하면 하나의 테스트를 수행하고 모두 잡는 것은 어떨까요 ??

<link href="//ajax.googleapis.com/ajax/libs/jqueryui/1/themes/start/jquery-ui.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script>
<script type="text/javascript">
    if (typeof jQuery == 'undefined') {
        document.write(unescape('%3Clink rel="stylesheet" type="text/css" href="../../Content/jquery-ui-1.8.16.custom.css" /%3E'));
        document.write(unescape('%3Cscript type="text/javascript" src="/jQuery/jquery-1.6.4.min.js" %3E%3C/script%3E'));
        document.write(unescape('%3Cscript type="text/javascript" src="/jQuery/jquery-ui-1.8.16.custom.min.js" %3E%3C/script%3E'));
    }
</script>

질문은 스타일 시트가로드되었는지 여부를 감지하는 것입니다. 한 가지 가능한 접근 방식은 다음과 같습니다.

1) CSS 파일 끝에 다음과 같은 특수 규칙을 추가합니다.

#foo { display: none !important; }

2) HTML에 해당 div를 추가합니다.

<div id="foo"></div>

3) 문서 준비 상태에서 #foo표시 여부를 확인합니다 . 스타일 시트가로드 된 경우 표시되지 않습니다.

여기 데모 -jquery-ui 부드러움 테마를로드합니다. 스타일 시트에 규칙이 추가되지 않습니다.


이 기사는 부트 스트랩 CSS http://eddmann.com/posts/providing-local-js-and-css-resources-for-cdn-fallbacks/에 대한 몇 가지 솔루션을 제안합니다 .

또는 이것은 fontawesome에서 작동합니다.

<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
<script>
    (function($){
        var $span = $('<span class="fa" style="display:none"></span>').appendTo('body');
        if ($span.css('fontFamily') !== 'FontAwesome' ) {
            // Fallback Link
            $('head').append('<link href="/css/font-awesome.min.css" rel="stylesheet">');
        }
        $span.remove();
    })(jQuery);
</script>

에서 스타일 시트의 존재 여부를 테스트 할 있습니다document.styleSheets .

var rules = [];
if (document.styleSheets[1].cssRules)
    rules = document.styleSheets[i].cssRules
else if (document.styleSheets[i].rules)
    rule= document.styleSheets[i].rules

Test for something specific to the CSS file you're using.


Here's an extension to katy lavallee's answer. I've wrapped everything in self-executing function syntax to prevent variable collisions. I've also made the script non-specific to a single link. I.E., now any stylesheet link with a "data-fallback" url attribute will automatically be parsed. You don't have to hard-code the urls into this script like before. Note that this should be run at the end of the <head> element rather than at the end of the <body> element, otherwise it could cause FOUC.

http://jsfiddle.net/skibulk/jnfgyrLt/

<link rel="stylesheet" type="text/css" href="broken-link.css" data-fallback="broken-link2.css">

.

(function($){
    var links = {};

    $( "link[data-fallback]" ).each( function( index, link ) {
        links[link.href] = link;
    });

    $.each( document.styleSheets, function(index, sheet) {
        if(links[sheet.href]) {
            var rules = sheet.rules ? sheet.rules : sheet.cssRules;
            if (rules.length == 0) {
                link = $(links[sheet.href]);
                link.attr( 'href', link.attr("data-fallback") );
            }
        }
    });
})(jQuery);

Do you really want to go down this javascript route to load CSS in case a CDN fails?

I haven't thought all the performance implications through but you're going to lose control of when the CSS is loaded and in general for page load performance, CSS is the first thing you want to download after the HTML.

Why not handle this at the infrastructure level - map your own domain name to the CDN, give it a short TTL, monitor the files on the CDN (e.g. using Watchmouse or something else), if CDN fails, change the DNS to backup site.

Other options that might help are "cache forever" on static content but there's no guarantee the browser will keep them of course or using the app-cache.

In reality as someone said at the top, if your CDN is unreliable get a new one

Andy


One could use onerror for that:

<link rel="stylesheet" href="cdn.css" onerror="this.onerror=null;this.href='local.css';" />

The this.onerror=null; is to avoid endless loops in case the fallback it self is not available. But it could also be used to have multiple fallbacks.

However, this currently only works in Firefox and Chrome.


Look at these functions:

$.ajax({
    url:'CSS URL HERE',
    type:'HEAD',
    error: function()
    {
        AddLocalCss();
    },
    success: function()
    {
        //file exists
    }
});

And here is vanilla JavaScript version:

function UrlExists(url)
{
    var http = new XMLHttpRequest();
    http.open('HEAD', url, false);
    http.send();
    return http.status!=404;
}
if (!UrlExists('CSS URL HERE') {
AddLocalCss();
}

Now the actual function:

function AddLocalCss(){
document.write('<link rel="stylesheet" type="text/css" href=" LOCAL CSS URL HERE">')
}

Just make sure AddLocalCss is called in the head.

You might also consider using one of the following ways explained in this answer:

Load using AJAX

$.get(myStylesLocation, function(css)
{
   $('<style type="text/css"></style>')
      .html(css)
      .appendTo("head");
});

Load using dynamically-created

$('<link rel="stylesheet" type="text/css" href="'+myStylesLocation+'" >')
   .appendTo("head");
Load using dynamically-created <style>

$('<style type="text/css"></style>')
    .html('@import url("' + myStylesLocation + '")')
    .appendTo("head");

or

$('<style type="text/css">@import url("' + myStylesLocation + '")</style>')
    .appendTo("head");

I'd probably use something like yepnope.js

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');
    }
  }
}]);

Taken from the readme.


//(load your cdn lib here first)

<script>window.jQuery || document.write("<script src='//me.com/path/jquery-1.x.min.js'>\x3C/script>")</script>

참고URL : https://stackoverflow.com/questions/7383163/how-to-fallback-to-local-stylesheet-not-script-if-cdn-fails

반응형