Como fornecer um fallback local para o Font Awesome se a CDN falhar?

13

Estou tentando desenvolver um tema do Wordpress e descobrir como fornecer um fallback local para o Font Awesome se a CDN falhar ou se eu desenvolver o meu tema em um servidor local sem conexão à Internet.

A solução que tenho em mente é algo como isto (pseudo-código):

if ( $CDN_IS_AVAILABLE ) { 
        wp_enqueue_style( 'font-awesome', '//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css', false );
    } else {
        wp_enqueue_style('font-awesome', get_template_directory_uri() . '/css/font-awesome/css/font-awesome.min.css', false, '4.0.3' );
    }

Obrigado!

Knott
fonte
1
Receio que a pergunta não seja específica do WordPress. Talvez essa pergunta se encaixe em você.
Mayeenul Islam
Por que você pensa isso? Estou falando sobre o desenvolvimento de um tema WordPress e de certos padrões (tf) que afirmam que, se uma versão CDN de uma biblioteca for incluída, uma cópia local deverá ser fornecida como substituta. Obrigado mesmo assim.
Knott
1
wp_enqueue_style()e como trabalhar com isso está no tópico.
fuxia
2
Existem - pelo menos - algumas maneiras, no entanto, a única razão para usar uma CDN é o desempenho, mas tenho certeza de que qualquer maneira que você encontrar piorará o desempenho, por isso imho não faz sentido. Se o tema for de compartilhamento / venda, eu optaria apenas pela cópia local, deixando aos usuários uma maneira fácil de mudar para a versão CDN, se preferirem. Se o tema for apenas para você, escolha um ou outro. Considere que as CDNs mais famosas têm um% muito baixo de tempo de inatividade (e o bootstrapcdn é um dos mais confiáveis, de acordo com o cdnperf.com ).
gmazzap
1
Bem, é claro que sim, eu nunca faria um pedido extra do PHP por isso. Esse é o desafio aqui - para iniciantes, não consigo pensar em uma boa maneira de verificar a carga de CSS.
Rarst

Respostas:

14

O problema é que tenho certeza de que é impossível verificar se o CSS é efetivamente adicionado a uma página via PHP: o CSS é analisado pelo navegador, portanto, do lado do cliente, e não tem nenhum efeito no servidor.

Obviamente, no PHP é possível verificar se o CDN é responsivo ou não ...

Opção 1

Envie uma solicitação e, se ela responder com o status HTTP 200, use-a. Algo como:

function font_awesome_css() {
    $url = 'http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css';
    $cdn = wp_remote_get( $url );
    if ( (int) wp_remote_retrieve_response_code( $cdn) !== 200 ) {
        $url = get_template_directory_uri() . '/css/font-awesome/css/font-awesome.min.css';
    }
    wp_enqueue_style( 'font-awesome', $url, false );
}

isso resulta em 2 solicitações HTTP, uma para a verificação e a segunda para CSS incorporado: muito ruim .

opção 2

function font_awesome_css() {
    $url = 'http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css';
    $cdn = wp_remote_get( $url );
    if ( (int) wp_remote_retrieve_response_code( $cdn ) === 200 ) {
        $css = wp_remote_retrieve_body( $cdn );
        add_action( 'wp_head', function() use( $css ) {
            $absolute = "//netdna.bootstrapcdn.com/font-awesome/4.0.3/fonts/";
            $css = str_replace( "../fonts/", $absolute, $css );
            echo '<style type="text/css">' . $css . '</style>';
        } );
    } else {
        $url = get_template_directory_uri() . '/css/font-awesome/css/font-awesome.min.css';
        wp_enqueue_style( 'font-awesome', $url, false );
    }
}

Isso é ainda pior :

  • Isso acaba com o wp_enqueue_stylefluxo de trabalho: se um plug-in adicionar Font Awesome, ele será adicionado 2 vezes.
  • O número de solicitações HTTP é o mesmo; no entanto, normalmente as 2 solicitações são executadas em paralelo , portanto, a geração de páginas do PHP diminui porque precisa aguardar a resposta da primeira solicitação.
  • Isso também impede que o navegador armazene em cache o CSS; portanto, se você usar o mesmo estilo em páginas diferentes, force a solicitação da CDN em todas as páginas visitadas. Ao usar o fluxo de trabalho normal, as páginas após o primeiro CSS são obtidas do cache.

Então, realmente, não faça isso em casa.

O que realmente importa é que, usando PHP, você pode verificar a solicitação da CDN, mas não a CSS, para que todos os seus esforços acabem com desempenho pior, em vez de melhor.

Atenciosamente, se o seu for um tema público, sugiro que você use apenas a cópia local, fornecendo aos usuários uma maneira de escolher uma CDN:

if ( ! function_exists( 'font_awesome_css' ) ) {
    function font_awesome_css() {
        $_url = get_template_directory_uri() . '/css/font-awesome/css/font-awesome.min.css';
        $url = apply_filters( 'font_awesome_css_url', $_url );
        wp_enqueue_style( 'font-awesome', $url, false );
    }
}

Assim, os usuários podem substituir completamente a função usando um tema filho e também podem usar o 'font_awesome css_url'filtro para alterar o URL.

Considere também que alguns provedores de hospedagem de ponta convertem automaticamente ativos locais em CDN e existem plugins que permitem à CDN tudo; esse é o motivo pelo qual um tema público não deve usar a CDN.

Se o tema é para você, faça uma escolha. Considere que as CDNs mais famosas têm um% muito baixo de tempo de inatividade (e o bootstrapcdn é um dos mais confiáveis, de acordo com o cdnperf.com ). Tenho certeza de que sua hospedagem tem um% de tempo de inatividade maior que o bootstrapcdn, para que as pessoas tenham mais probabilidade de não ver seu site, do que de ícones quebrados.

O caminho sujo

Como dito, o PHP não pode verificar o CSS, porque a renderização do CSS ocorre no lado do cliente, mas você pode usar a verificação no lado do cliente: JavaScript.

Primeiro incorpore CSS usando CDN:

function font_awesome_css() {
    $url =  '//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css';
    wp_enqueue_style( 'font-awesome', $url, false );
} 

Depois disso, adicione um pouco de JavaScript ao rodapé:

/*
Normally the JS should be properly enqueued and the URL
passed via wp_enqueue_script, but this is a proof of concept,
more than real code.
*/
add_action( 'wp_footer', function() {
    $cssurl = get_template_directory_uri() . '/css/';
    ?>
    <span id="facheck" data-cssuri="<?php echo $cssurl; ?>" class="fa" style="display:none">
    </span>
    <script>
        jQuery(document).ready(function($) {
            var $check = $('#facheck');
            if ( $check.css('fontFamily') !== 'FontAwesome' ) {
                // Font Awesome not loaded!
                // Remove current CSS link
                $('#font-awesome-css').remove;
                // Add the local version
                var local = '<link rel="stylesheet" type="text/css" href="' +
                    $check.data('cssuri') + // This is the theme CSS folder URL
                    'font-awesome/css/font-awesome.min.css" />';
                $('head').append( local );
            }
        });
    </script>
    <?php
});

Esse código é executado quando a página é carregada e verifica se a extensão invisível adicionada ao rodapé com a classe 'fa' tem a propriedade da família de fontes definida como 'FontAwesome'. Isso é definido pelo Font Awesome, portanto, se não for verdade, significa que o CSS não está carregado. Se isso acontecer, o código usa JavaScript para anexar o CSS local à cabeça.

(Para testar esse código, você pode incorporar através de wp_enqueue_styleum URL CDN errado e ver o que acontece)

Portanto, no caso raro de uma CDN não estar disponível, todos os estilos serão mostrados conforme o esperado (por alguns milissegundos, os usuários verão ícones CSS "quebrados", porque o CSS é adicionado após o carregamento da página).

Agora, considerando que as CDNs são muito confiáveis, vale a pena fazer esse truque para <1% das pessoas que verão ícones quebrados? A resposta a esta pergunta é deixada para você.

gmazzap
fonte
Há muito tempo não vejo uma abordagem tão complexa e profunda sobre um tópico como este. Isso me limpou completamente. Agora, acho que vou usar a CDN apenas como uma opção de tema, deixando a liberdade de escolha do usuário. Obrigado!
Knott
Há muito tempo que estou procurando uma solução como essa, então, com relação à última frase que pergunta "vale a pena fazer esse truque para <1% das pessoas que verão ícones quebrados?" Talvez adicionar um spinner de carregamento funcionasse?
Carl Alberto
1

Uma verificação do lado do servidor também não é à prova de balas. Se o seu servidor estiver localizado na Califórnia, seu cheque usará o Data Center da CDN da Califórnia. Se seu usuário estiver localizado na China, provavelmente usará um Data Center completamente diferente. Pelo menos, é assim que acho que funciona.

De qualquer forma, aqui está uma solução jquery aprimorada:

http://jsfiddle.net/skibulk/fp1gqnyc/

<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="/wordpress//css/font-awesome.min.css" rel="stylesheet">');
        }
        $span.remove();
    })(jQuery);
</script>
skibulk
fonte
brilhante e uma abordagem válida por muito mais do que incríveis fontes, obrigado por compartilhar. Devo acrescentar, também agnóstico, ao contrário das outras soluções aqui e em outros lugares do SO, por exemplo.
oucil
1
Como não há tempo limite, isso acabará carregando o Font Awesome duas vezes se a instância da CDN terminar de carregar após a verificação fontFamily.
Dan Dascalescu 29/08/2015
@DanDascalescu Os arquivos CSS não são carregados de forma síncrona (bloqueio) por padrão? Acredito que a página não continuará até que a CDN seja carregada ou falhe?
Skibulk 30/08/2015
O CSS é carregado de forma síncrona, mas a fonte em si é carregada apenas quando o texto usado é renderizado. Aqui está um JSbin mostrando isso .
Dan Dascalescu 30/08/2015