Neste codelab, você aprenderá a integrar um service worker a um aplicativo existente para que o aplicativo funcione off-line. O aplicativo se chama Air Horner. Clique na buzina e ela faz um som.
Clone o repositório do GitHub pela linha de comando sobre SSH:
$ git clone git@github.com:GoogleChrome/airhorn.git
Ou HTTPS:
$ git clone https://github.com/GoogleChrome/airhorn.git
Primeiro, vejamos qual a aparência do aplicativo de exemplo acabado (dica: é incrível).
Certifique-se de que você esteja na ramificação correta (final), verificando a ramificação master
.
$ git checkout master
Execute o site a partir de um servidor de Web local. Você pode usar qualquer servidor de Web, mas pelo resto deste
codelab vamos supor que esteja usando SimpleHTTPServer
do Python na porta 3000, portanto o aplicativo
estará disponível em localhost:3000
.
$ cd app
$ python -m SimpleHTTPServer 3000
Abra o site no Chrome. Você deve ver:
Clique na buzina. Ela deve fazer um som.
Agora, você vai simular ficar off-line usando Chrome DevTools.
Abra o DevTools, vá ao painel Application, e ative a caixa de seleção Offline. Na imagem abaixo, o cursor está parado sobre a caixa de seleção.
Após clicar na caixa de seleção, observe o ícone de aviso (triângulo amarelo com ponto de exclamação) ao lado da guia Network do painel. Isto indica que você está off-line.
Para provar que você está off-line, vá para https://google.com. Você deve ver a mensagem de erro "não há conexão com a Internet" do Chrome.
Agora, volte para o seu aplicativo. Embora esteja off-line, a página ainda deve atualizar totalmente. Você ainda deve conseguir usar a buzina.
O motivo para ele funcionar off-line é a base deste codelab: suporte off-line com o service worker.
Agora você vai remover todo o suporte off-line do aplicativo e vai aprender como usar um service worker para adicionar o suporte off-line de volta ao aplicativo
Confira a versão "quebrada" do aplicativo que não tem o service worker implementado.
$ git checkout code-lab
Volte ao painel Application do DevTools e desative a caixa de seleção Offline, para voltar a ficar online.
Execute a página. O aplicativo deve funcionar da forma esperada.
Agora, use DevTools para simular o modo off-line novamente (ativando a caixa de seleção Offline no painel Application). Atenção! Se não sabe muito sobre service workers, você está prestes a ver um comportamento inesperado.
O que você espera ver? Bem, como está off-line e esta versão do aplicativo não tem service worker, seria de esperar ver a mensagem de erro "não há conexão com a Internet" típica do Chrome.
Mas o que você realmente vê é ... um aplicativo off-line totalmente funcional!
O que aconteceu? Bem, lembre-se de que ao começar este codelab, você experimentou a versão concluída do aplicativo.
Quando aquela versão foi executada, o aplicativo realmente instalou um service worker. Esse service worker agora
está sendo executado automaticamente toda vez que você executa o aplicativo. Uma vez que um service worker é instalado
para um escopo, como localhost:3000
(você vai aprender mais sobre escopo na próxima seção), esse service
worker é iniciado automaticamente toda vez que se acessa o escopo, a menos que você o exclua programática ou manualmente.
Para corrigir isso, vá para o painel Application do DevTools, clique na guia Service Workers e, em seguida, clique no botão Unregister. Na imagem abaixo, o cursor está parado sobre o botão.
Agora, antes de atualizar o site, certifique-se de que você ainda está usando DevTools para simular o modo off-line. Atualize a página, e ela deve exibir a mensagem de erro "não há conexão com a Internet", como esperado.
Agora é hora de adicionar suporte off-line de volta ao aplicativo. Isso consiste em dois passos:
Primeiro, crie um arquivo vazio chamado sw.js
e coloque-o na pasta /app
.
Agora, abra index.html
e adicione o código a seguir na parte inferior de <body>
.
<script>
if('serviceWorker' in navigator) {
navigator.serviceWorker
.register('/sw.js')
.then(function() { console.log("Service Worker Registered"); });
}
</script>
O script verifica se o navegador suporta service workers. Se suportar, ele registra o nosso arquivo sw.js
atualmente em branco como o service worker, e, em seguida, registra para o console.
Antes de executar seu site novamente, volte para DevTools e olhe a guia Service Workers do painel Application. Ela deve ser atualmente vazia, o que significa que o site não tem service workers instalados.
Certifique-se de que a caixa de seleção Offline no DevTools esteja desativada. Atualize sua página novamente. Como a página é carregada, você pode ver que um service worker está registrado.
Ao lado do rótulo Source, você pode ver um link para o código-fonte do service worker registrado.
Se quiser inspecionar o service worker atualmente instalado para uma página, clique no link. Isso vai exibir o código-fonte do service worker no painel Sources do DevTools. Por exemplo, clique no link agora, e você deve ver um arquivo vazio.
Com o service worker registrado, na primeira vez que um usuário acessar a página, um evento install
é
acionado. Este evento é o local onde você deseja armazenar em cache os ativos da sua página.
Adicione o código a seguir ao sw.js.
importScripts('/cache-polyfill.js');
self.addEventListener('install', function(e) {
e.waitUntil(
caches.open('airhorner').then(function(cache) {
return cache.addAll([
'/',
'/index.html',
'/index.html?homescreen=1',
'/?homescreen=1',
'/styles/main.css',
'/scripts/main.min.js',
'/sounds/airhorn.mp3'
]);
})
);
});
A primeira linha adiciona o Cache polyfill. Este polyfill já está incluído no repositório. Precisamos usar o polyfill
porque a API Cache ainda não é totalmente suportada em todos os navegadores. Em seguida, vem o ouvinte de evento
install
. O ouvinte de evento install
abre o objeto caches
e, em seguida, o
preenche com a lista de recursos que queremos armazenar em cache. Uma coisa importante sobre a operação addAll
é que ela é tudo ou nada. Se um dos arquivos não estiver presente ou não for buscado, toda a operação addAll
falha. Um bom aplicativo cuidará desse cenário.
O próximo passo é programar nosso service worker para retornar a interceptação das solicitações de qualquer um desses
recursos e usar o objeto caches
para retornar a versão armazenada localmente de cada recurso.
Um recurso poderoso dos service workers é que, uma vez que um service worker controla uma página, ele pode interceptar todas as solicitações que a página faz e decidir o que fazer com a solicitação. Nesta seção você vai programar o service worker para interceptar solicitações e retornar as versões em cache de ativos, em vez de ir para a rede para recuperá-los.
A primeira etapa é anexar um gerenciador de eventos ao evento fetch
. Esse evento é acionado para todas
as solicitações realizadas.
Adicione o código a seguir ao à parte inferior do seu sw.js
para registrar as solicitações feitas a partir
da página principal.
Vamos testar isso. Atenção! Você está prestes a ver mais algum comportamento inesperado do service worker.
Abra DevTools e vá para o painel Application. A caixa de seleção Offline deve estar
desativada. Pressione a tecla Esc
para abrir a gaveta Console na parte inferior da
sua janela DevTools. Sua janela DevTools deve ser semelhante à imagem a seguir:
Atualize sua página agora e veja a janela de DevTools novamente. Para começar, esperamos ver várias solicitações registradas no Console, mas isso não está acontecendo. Em segundo lugar, no painel Service Worker podemos ver que o Status mudou:
No Status há um novo service worker esperando para ativar. Este deve ser o novo service worker que
inclui as alterações que acabamos de fazer. Então, por algum motivo, o antigo service worker que instalamos (que
era apenas um arquivo em branco) ainda está controlando a página. Se clicar no link sw.js
ao lado de
Source você pode verificar que o antigo service worker ainda está em execução.
Para corrigir esse inconveniente, ative a caixa de seleção Update on reload.
Quando esta caixa de seleção está ativada, DevTools sempre atualiza o service worker a cada atualização da página. Isso é muito útil ao se desenvolver um service worker ativamente.
Atualize a página agora e você pode ver que um novo service worker está instalado e que os URLs de solicitação estão sendo registrados no Console, como esperado.
Agora você precisa decidir o que fazer com todas essas solicitações. Por padrão, se você não fizer nada, a solicitação é transmitida para a rede e a resposta é retornada para a página da Web.
Para que seu aplicativo funcione off-line, você precisa coletar a solicitação do cache se ela estiver disponível.
Atualize seu ouvinte de evento de busca para coincidir com o código abaixo.
O método event.respondWith()
informa ao navegador para avaliar o resultado do evento no futuro. caches.match(event.request)
leva a atual solicitação da web que ativou o evento de busca e procura no cache por um recurso que corresponda. A
correspondência é realizada verificando a string do URL. O método match
retorna uma promessa que resolve,
mesmo se o arquivo não for encontrado no cache. Isso significa que você tem uma escolha sobre o que fazer. Em nosso
caso simples, quando o arquivo não é encontrado, você deve fetch
o mesmo da rede e retorná-lo ao navegador.
Este é o caso mais simples; existem muitos outros cenários de armazenamento em cache. Por exemplo, é possível armazenar em cache de forma incremental todas as respostas de solicitações que anteriormente não estavam armazenadas para que, no futuro, todas sejam retornadas do cache.
Agora você tem suporte off-line. Atualize a página enquanto ainda está online para atualizar o service worker para a última versão, e depois use DevTools para entrar em modo off-line. Atualizar a página novamente, e você deve ter uma buzina de ar off-line totalmente funcional!