Este codelab faz parte do curso de treinamento "Desenvolvimento de Apps Web Progressivos", desenvolvido pela equipe de treinamento do Google Developers. Você vai aproveitar mais este curso se fizer os codelabs em sequência.
Para detalhes completos sobre o curso, consulte a visão geral sobre o desenvolvimento de Progressive Web Apps.
Introdução
Neste laboratório, você vai criar um service worker simples e entender o ciclo de vida dele.
O que você vai aprender
- Criar e instalar um script de service worker básico e fazer uma depuração simples
O que você precisa saber
- JavaScript e HTML básicos
- Conceitos e sintaxe básica das Promises do ES2015
- Como ativar o console do desenvolvedor
O que você precisa antes de começar
- Computador com acesso ao terminal/shell
- Conexão com a Internet
- Um navegador compatível com service workers
- Um editor de texto
Faça o download ou clone o repositório pwa-training-labs do GitHub e instale a versão LTS do Node.js, se necessário.
Navegue até o diretório service-worker-lab/app/ e inicie um servidor de desenvolvimento local:
cd service-worker-lab/app npm install node server.js
Você pode encerrar o servidor a qualquer momento com Ctrl-c.
Abra o navegador e acesse localhost:8081/.
Observação:cancele o registro de todos os service workers e limpe todos os caches deles para localhost para que não interfiram no laboratório. No Chrome DevTools, clique em Limpar dados do site na seção Limpar armazenamento da guia Aplicativo.
Abra a pasta service-worker-lab/app/ no editor de texto de sua preferência. A pasta app/ é onde você vai criar o laboratório.
Essa pasta contém:
below/another.html,js/another.js,js/other.jseother.htmlsão recursos de exemplo que usamos para testar o escopo do service worker.- A pasta
styles/contém as folhas de estilo em cascata deste laboratório. - A pasta
test/contém arquivos para testar seu progresso. index.htmlé a página HTML principal do nosso site/aplicativo de exemplo.service-worker.jsé o arquivo JavaScript usado para criar nosso service worker.package.jsonepackage-lock.jsonrastreiam os pacotes de nós usados neste projeto.server.jsé um servidor express simples que usamos para hospedar nosso app.
Abra service-worker.js no seu editor de texto. O arquivo está vazio. Ainda não adicionamos nenhum código para ser executado no service worker.
Abra index.html no seu editor de texto.
Dentro das tags <script>, adicione o seguinte código para registrar o service worker:
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('service-worker.js')
.then(registration => {
console.log('Service Worker is registered', registration);
})
.catch(err => {
console.error('Registration failed:', err);
});
});
}Salve o script e atualize a página. O console vai retornar uma mensagem indicando que o service worker foi registrado. No Chrome, é possível verificar se um service worker está registrado abrindo o DevTools (Ctrl + Shift + I no Windows e Linux ou ⌘ + alt + I no Mac), clicando na guia "Application" e depois na opção Service Workers. O resultado será semelhante ao seguinte:

Opcional: abra o site em um navegador não compatível e verifique se a condição de verificação de suporte funciona.
Explicação
O código acima registra o arquivo service-worker.js como um service worker. Primeiro, ele verifica se o navegador é compatível com service workers. Isso deve ser feito sempre que você registrar um service worker, porque alguns navegadores podem não ser compatíveis com eles. Em seguida, o código registra o service worker usando o método register da API ServiceWorkerContainer, que está contida na interface Navigator da janela.
navigator.serviceWorker.register(...) retorna uma promessa que é resolvida com um objeto registration quando o service worker é registrado. Se o registro falhar, a promessa será rejeitada.
Mudanças no status do service worker acionam eventos nele.
Adicione listeners de eventos
Abra service-worker.js no seu editor de texto.
Adicione os seguintes listeners de eventos ao service worker:
self.addEventListener('install', event => {
console.log('Service worker installing...');
// Add a call to skipWaiting here
});
self.addEventListener('activate', event => {
console.log('Service worker activating...');
});Salve o arquivo.
Cancele manualmente o registro do service worker e atualize a página para instalar e ativar o service worker atualizado. O registro do console deve indicar que o novo service worker foi registrado, instalado e ativado.
Observação : o registro de inscrição pode aparecer fora de ordem com os outros registros (instalação e ativação). O service worker é executado simultaneamente com a página, então não podemos garantir a ordem dos registros. O registro de inscrição vem da página, enquanto os registros de instalação e ativação vêm do service worker. A instalação, a ativação e outros eventos do service worker ocorrem em uma ordem definida dentro dele e sempre aparecem na ordem esperada.
Explicação
O service worker emite um evento install ao final do registro. No código acima, uma mensagem é registrada no listener de eventos install, mas em um app do mundo real, esse seria um bom lugar para armazenar ativos estáticos em cache.
Quando um service worker é registrado, o navegador detecta se ele é novo (porque é diferente do service worker instalado anteriormente ou porque não há um service worker registrado para esse site). Se o service worker for novo (como neste caso), o navegador vai instalá-lo.
O service worker emite um evento activate quando assume o controle da página. O código acima registra uma mensagem aqui, mas esse evento é usado com frequência para atualizar caches.
Apenas um service worker pode ficar ativo por vez em um determinado escopo (consulte "Explorando o escopo do service worker"), então um service worker recém-instalado não é ativado até que o service worker atual não esteja mais em uso. Por isso, todas as páginas controladas por um service worker precisam ser fechadas antes que um novo possa assumir o controle. Como cancelamos a inscrição do service worker atual, o novo foi ativado imediatamente.
Observação:apenas atualizar a página não é suficiente para transferir o controle para um novo service worker, porque a nova página será solicitada antes do descarregamento da página atual, e não haverá um momento em que o service worker antigo não esteja em uso.
Observação:também é possível ativar manualmente um novo service worker usando a ferramenta de desenvolvedor de alguns navegadores e de maneira programática com skipWaiting(), que discutimos na seção 3.4.
Atualizar o service worker
Adicione o seguinte comentário em qualquer lugar em service-worker.js:
// I'm a new service workerSalve o arquivo e atualize a página. Confira os registros no console. Observe que o novo service worker é instalado, mas não ativado. No Chrome, é possível ver o service worker em espera na guia Aplicativo do DevTools.

Feche todas as páginas associadas ao service worker. Em seguida, reabra o localhost:8081/. O registro do console vai indicar que o novo service worker foi ativado.
Observação:se você estiver recebendo resultados inesperados, verifique se o cache HTTP está desativado nas ferramentas para desenvolvedores.
Explicação
O navegador detecta uma diferença de bytes entre o arquivo do service worker novo e o existente (devido ao comentário adicionado). Assim, o novo service worker é instalado. Como apenas um service worker pode estar ativo por vez (para um determinado escopo), mesmo que o novo service worker seja instalado, ele não será ativado até que o service worker atual não esteja mais em uso. Ao fechar todas as páginas sob o controle do service worker antigo, é possível ativar o novo.
Pular a fase de espera
É possível que um novo service worker seja ativado imediatamente, mesmo que um service worker já esteja presente, pulando a fase de espera.
Em service-worker.js, adicione uma chamada para skipWaiting no listener de eventos install:
self.skipWaiting();Salve o arquivo e atualize a página. O novo service worker é instalado e ativado imediatamente, mesmo que um service worker anterior estivesse no controle.
Explicação
O método skipWaiting() permite que um service worker seja ativado assim que a instalação for concluída. O listener de eventos de instalação é um lugar comum para colocar a chamada skipWaiting(), mas ela pode ser chamada em qualquer lugar durante ou antes da fase de espera. Consulte esta documentação para saber quando e como usar skipWaiting(). No restante do laboratório, podemos testar um novo código de service worker sem cancelar o registro dele manualmente.
Para saber mais
Os service workers podem atuar como um proxy entre seu app da Web e a rede.
Vamos adicionar um listener de busca para interceptar solicitações do nosso domínio.
Adicione o código a seguir a service-worker.js:
self.addEventListener('fetch', event => {
console.log('Fetching:', event.request.url);
});Salve o script e atualize a página para instalar e ativar o service worker atualizado.
Verifique o console e observe que nenhum evento de busca foi registrado. Atualize a página e verifique o console de novo. Desta vez, você vai ver eventos de busca para a página e os recursos dela (como CSS).
Clique nos links Outra página, Outra página e Voltar.
Você vai ver eventos de busca no console para cada uma das páginas e seus recursos. Todos os registros fazem sentido?
Observação:se você acessar uma página e não tiver desativado o cache HTTP, os recursos CSS e JavaScript poderão ser armazenados em cache localmente. Se isso acontecer, você não vai ver eventos de busca para esses recursos.
Explicação
O service worker recebe um evento de busca para cada solicitação HTTP feita pelo navegador que está dentro do escopo dele. O objeto evento de busca contém a solicitação. A detecção de eventos de busca no service worker é semelhante à detecção de eventos de clique no DOM. No nosso código, quando um evento de busca ocorre, registramos o URL solicitado no console. Na prática, também podemos criar e retornar nossa própria resposta personalizada com recursos arbitrários.
Por que nenhum evento de busca foi registrado na primeira atualização? Por padrão, os eventos de busca de uma página não passam por um service worker, a menos que a solicitação da página tenha passado por um. Isso garante a consistência no site. Se uma página for carregada sem o service worker, o mesmo vai acontecer com os sub-recursos dela.
Para saber mais
Código da solução
Para receber uma cópia do código em funcionamento, navegue até a pasta 04-intercepting-network-requests/.
Os service workers têm escopo. O escopo do service worker determina de quais caminhos ele intercepta solicitações.
Encontrar o escopo
Atualize o código de registro em index.html com:
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('service-worker.js')
.then(registration => {
console.log('SW registered with scope:', registration.scope);
})
.catch(err => {
console.error('Registration failed:', err);
});
});
}Atualize o navegador. O console mostra o escopo do service worker (neste caso, http://localhost:8081/).
Explicação
A promessa retornada por register() é resolvida para o objeto de registro, que contém o escopo do service worker.
O escopo padrão é o caminho para o arquivo do service worker e se estende a todos os diretórios inferiores. Assim, um service worker no diretório raiz de um app controla solicitações de todos os arquivos no app.
Mover o service worker
Mova service-worker.js para o diretório below/ e atualize o URL do service worker no código de registro em index.html.
Cancele o registro do service worker atual no navegador e atualize a página.
O console mostra que o escopo do service worker agora é http://localhost:8081/below/. No Chrome, você também pode ver o escopo do service worker na guia "Aplicativo" do DevTools:

De volta à página principal, clique em Outra página, Outra página e Voltar. Quais solicitações de busca estão sendo registradas? Quais não são?
Explicação
O escopo padrão do service worker é o caminho para o arquivo dele. Como o arquivo do service worker agora está em below/, esse é o escopo dele. Agora, o console só registra eventos de busca para another.html, another.css e another.js, porque esses são os únicos recursos no escopo do service worker.
Definir um escopo arbitrário
Mova o service worker de volta para o diretório raiz do projeto (app/) e atualize o URL do service worker no código de registro em index.html.
Use a referência na MDN para definir o escopo do service worker no diretório below/ usando o parâmetro opcional em register().
Cancele a inscrição do service worker e atualize a página. Clique em Outra página, Mais uma página e Voltar.
Novamente, o console mostra que o escopo do service worker agora é http://localhost:8081/below/ e registra eventos de busca apenas para another.html, another.css e another.js.
Explicação
É possível definir um escopo arbitrário transmitindo um parâmetro adicional ao registrar, por exemplo:
navigator.serviceWorker.register('/service-worker.js', {
scope: '/kitten/'
});No exemplo acima, o escopo do service worker é definido como /kitten/. O service worker intercepta solicitações de páginas em /kitten/ e /kitten/lower/, mas não de páginas como /kitten ou /.
Observação:não é possível definir um escopo arbitrário acima do local real do service worker. No entanto, se o service worker estiver ativo em um cliente atendido com o cabeçalho Service-Worker-Allowed, você poderá especificar um escopo máximo para esse service worker acima da localização dele.
Para saber mais
Código da solução
Para receber uma cópia do código em funcionamento, navegue até a pasta solution/.
Agora você tem um service worker simples em execução e entende o ciclo de vida dele.
Para saber mais
Para conferir todos os codelabs do curso de treinamento de PWA, consulte o codelab de boas-vindas do curso.