Como fazer um blog Jekyll funcionar offline usando service workers
Publicados: 2017-01-26Bytes curtos: Você sabia que com o advento dos Service Workers, pode-se começar a fazer os sites funcionarem offline! Esses aplicativos da Web são chamados de PWAs (Progressive Web Apps). Neste tutorial, vou ajudá-lo a usar um service worker para fazer um blog/site baseado em Jekyll funcionar offline e algumas coisas legais que vêm com ele.
(NOTA : Os trechos de código no artigo são retirados do repositório de código do meu blog. Ele pode ser consultado se necessário. Se você é novo no Jekyll, você pode ler o artigo da série 3 sobre truques de CSS.)
FUNDO
Anteriormente, costumava haver um Cache de Aplicativo baseado em arquivo YAML yuk, que era muito codificado por natureza e não podia ser usado para armazenar ativos e páginas da Web em cache dinamicamente. Entrem, Trabalhadores de Serviço. API Javascript simples baseada em eventos simples para fazer o cache dinâmico do service worker para armazenar ativos, para que possam ser usados para servir as páginas da Web quando não houver rede.
Os service workers chegaram ao Chrome Canary em 2014, mas sua especificação ainda está sendo revisada/adicionada e projetada. Em 2015 e 2016, a equipe do Google Chrome divulgou fortemente essa nova tecnologia nos navegadores. Apenas a Apple não suportava isso (mesmo no momento da redação deste artigo) em seus dispositivos (por razões desconhecidas) [Eles também não estão participando ativamente de nenhuma discussão de especificações sobre trabalhadores de serviços].
O que é um trabalhador de serviço? Basicamente, é um trabalhador da web em esteróides. Uma característica de um web worker é que todas as tarefas de um web worker são executadas separadamente (de forma assíncrona) do thread de execução JavaScript principal (loop de evento). Esse recurso ajuda a executar tarefas com uso intensivo de CPU ou memória, por exemplo, cálculos complicados sem comprometer o desempenho da interface do usuário do aplicativo da web.
O Service Worker nos permite armazenar em cache (armazenar por um longo tempo) ativos, como JavaScript, CSS, HTML, imagem, arquivos de fonte no cache do service worker do navegador, para que na próxima vez que o usuário carregar essa página, ela seja carregada quase instantaneamente . E também, como nessa estratégia de cache, o navegador procura a disponibilidade dos ativos primeiro no cache do service worker, a página da Web é atendida mesmo quando está offline! Se algum ativo não estiver no cache, uma solicitação de rede será enviada para buscá-lo.
Service worker também habilita as notificações push que são comuns em muitos sites hoje em dia, incluindo Facebook, Whatsapp na web e Twitter. Falaremos principalmente sobre o recurso offline. Este tutorial é específico para Jekyll, no entanto, a maior parte do código do service worker pode ser aplicada a qualquer site.
Como o Jekyll fornece conteúdo estático ( é um gerador de site estático, duh! ), nosso código de service worker seria muito básico e fácil de entender.
VAMOS ROLAR:
Em todas as páginas relevantes, o seguinte script é executado. Está fazendo as seguintes coisas:
- Verificando a existência da API do service worker no navegador e registrando o service worker.
- Quando o service worker for ativado, coloque uma bela mensagem de brinde/chip para o usuário de que o site está pronto para ser usado offline agora.
function showOfflineToast() { let offlineToast = document.querySelector('.offline-ready'); offlineToast.classList.add('active'); setTimeout(function(){ offlineToast.className = offlineToast.className.replace("active", "").trim(); }, 5500); } // (1) if (navigator.serviceWorker) { navigator.serviceWorker.register('/sw.js').then(function(reg) { if (!reg.installing) return; console.log("[*] ServiceWorker está instalando..."); var trabalhador = reg.installing; worker.addEventListener('statechange', function() { if (worker.state == 'redundante') { console.log('[*] Falha na instalação'); } if (worker.state == 'instalado') { console.log('[*] Instalação bem sucedida!'); } // (2) if (worker.state == 'ativado' && !navigator.serviceWorker.controller) { showOfflineToast(); } }); }); }
Você pode adicionar este pedaço de código em um arquivo como serviceWorker.html dentro do diretório includes do seu código Jekyll e incluí-lo em default.html usando o mecanismo de modelagem líquida do Jekyll
<!DOCTYPEhtml> <html> {% include head.html %} <corpo> {% include header.html %} <div class="page-content"> <div class="wrapper"> {{ contente }} </div> </div> {% include footer.html %} <!-- Contém o código acima em uma tag de script--> {% include serviceWorker.html %} <div class="offline-ready">O site está pronto para uso offline</div> </body> </html>
Agora, para o código real do service worker que faz a mágica. Este código reside em sw.js na raiz do seu código Jekyll.
//sw.js --- esquema: nulo --- const staticCacheName = "gdad-s-river-static-v61"; console.log("instalando o service worker"); const arquivosToCache = [ "/", {% para página em site.html_pages %} '{{ URL da página }}', {% endfor %} {% para postagem em site.posts %} '{{ post.url }}', {% endfor %} // pode ser automatizado em vez de entradas manuais "/assets/images/bhavri-github-callbacks.png", "/assets/images/bhavri-github-issues.png", "/assets/images/jakethecake-svg-line-anime.png", "/assets/images/svg-animated-mast-text-shapes-tweet.png", "css/main.css", "/cerca de/", "/index.html" ];
staticCacheName é a versão de cache que deve ser atualizada toda vez que eu fizer algumas alterações nas respostas em cache (por exemplo, eu faço uma alteração em um arquivo CSS ou uma postagem de blog). E estou apenas definindo quais solicitações quero interceptar e armazenar em cache em uma matriz (usada no próximo trecho).
//sw.js self.addEventListener("instalar", function(e){ self.skipWaiting(); e.waitAté( caches.open(staticCacheName).then(function(cache){ return cache.addAll(filesToCache); }) ) });
self.skipWaiting , quer dizer, que toda vez que esse arquivo sw.js for alterado, a versão mais recente do service worker não deve ser enfileirada, mas ativada imediatamente (pode-se solicitar que o usuário atualize a página dando uma mensagem como A página da Web foi atualizada/alterada, clique em Atualizar para carregar novas postagens ou qualquer outra coisa. ), jogando fora a versão mais antiga.
e.waitUntil citando o site da MDN:
“O método ExtendableEvent.waitUntil() estende o tempo de vida do evento. Em service workers, estender a vida útil de um evento impede que o navegador encerre o service worker antes que as operações assíncronas dentro do evento sejam concluídas.”
Eu abro um cache chamado gdad-s-river-static-v61 , que retorna uma promessa com meu nome de cache, e então chamo cache.addAll (que usa a API de busca em segundo plano), que busca todas as solicitações no array fornecido e os armazena em cache.
Vamos para o próximo trecho!
//sw.js self.addEventListener("ativar", function(e){ e.waitAté( caches.keys().then(function(cacheNames){ return Promessa.todos( cacheNames.filter(function(cacheName){ return cacheName.startsWith("gdad-s-river-static-") && cacheName != staticCacheName; }).map(function(cacheName){ return cache.delete(cacheName); }) )ß }) ) });
Quando o service worker é ativado, garanto que qualquer service worker que não seja a versão mais recente seja excluído. Por exemplo, se minha versão de cache mais recente for gdad-s-river-static-v61 , e alguém ainda estiver em gdad-s-river-static-v58 , em sua próxima visita, quero que esse cliente não se importe com bombeando uma versão de cada vez, mas exclua diretamente essa versão para instalar a mais recente.
//sw.js self.addEventListener("buscar", function(e){ e.respondaCom( caches.match(e.request).then(function(response) { resposta de retorno || buscar(e.request); }) ) });
No evento de busca, estou simplesmente dizendo ao service worker como responder a uma solicitação específica feita (já que estamos sequestrando a resposta dando poder, os service workers só funcionam em sites de origem https seguros). Digo a ele para corresponder a solicitação aos armazenados em cache no navegador e, se não encontrar essa resposta específica à solicitação, busque-a pela rede, senão a servirá a partir do cache.
Tada! Service worker deixou o blog com Jekyll offline!
SURPRESA! O LINDO:
Bummer: Isso não funcionaria em dispositivos iOS.
Se você adicionar um arquivo manifest.json de aplicativo da Web na raiz do projeto como este:
{ "name": "gdad-s-rio", "short_name": "gdad-s-rio", "theme_color": "#2196f3", "background_color": "#2196f3", "display": "autônomo", "Alcance": "/", "start_url": "/", "ícones": [ { "src": "assets/images/favicon_images/android-icon-36x36.png", "tamanhos": "36x36", "tipo": "imagem\/png", "densidade": "0,75" }, { "src": "assets/images/favicon_images/android-icon-48x48.png", "tamanhos": "48x48", "tipo": "imagem\/png", "densidade": "1,0" }, { "src": "assets/images/favicon_images/android-icon-72x72.png", "tamanhos": "72x72", "tipo": "imagem\/png", "densidade": "1,5" }, { "src": "assets/images/favicon_images/android-icon-96x96.png", "tamanhos": "96x96", "tipo": "imagem\/png", "densidade": "2,0" }, { "src": "assets/images/favicon_images/android-icon-144x144.png", "tamanhos": "144x144", "tipo": "imagem\/png", "densidade": "3,0" }, { "src": "assets/images/favicon_images/android-icon-192x192.png", "tamanhos": "192x192", "tipo": "imagem\/png", "densidade": "4.0" } ] }
e adicione-o no arquivo head.html dentro da tag head,
<cabeça> <!-- algumas coisas --> <link rel="manifest" href="/manifest.json"> <!-- algumas coisas --> </head>
Em seguida, na segunda visita ao seu site (em 5 minutos), solicitará que o usuário adicione seu site à tela inicial (para residir com um ícone, assim como outros aplicativos nativos), com o qual você se envolverá da mesma forma um aplicativo.
RECURSOS
- Detalhes dos recursos offline do service worker e estratégias de cache podem ser encontrados no livro de receitas offline deste incrível Jake Archibald.
- Um curso gratuito muito detalhado da Udacity sobre tudo o que você precisa saber sobre service workers e IndexDB.
Você achou este artigo no Jekyll Blog interessante e útil? Não se esqueça de compartilhar suas opiniões e comentários.
Leia também : Ecosia — O mecanismo de busca que planta árvores