Progressive Web Apps: ficando off-line

1. Olá!

Neste laboratório, você vai pegar um aplicativo da Web e fazê-lo funcionar off-line. Este é o primeiro de uma série de codelabs complementares para o workshop de App Web Progressivo. Há mais sete codelabs nesta série.

O que você vai aprender

  • Escrever um service worker manualmente
  • Adicionar um service worker a um aplicativo da Web
  • Use o service worker e a API Cache Storage para disponibilizar recursos off-line

O que você precisa saber

  • HTML e JavaScript básicos

O que é necessário

2. Começar a configuração

Comece clonando ou fazendo o download do código inicial necessário para concluir este codelab:

Se você clonar o repositório, verifique se está na ramificação starter. O arquivo zip também contém o código dessa ramificação.

Essa base de código exige o Node.js 14 ou versões mais recentes. Quando o código estiver disponível, execute npm ci na linha de comando da pasta do código para instalar todas as dependências necessárias. Em seguida, execute npm start para iniciar o servidor de desenvolvimento do codelab.

O arquivo README.md do código-fonte explica todos os arquivos distribuídos. Além disso, estes são os principais arquivos com que você vai trabalhar ao longo deste codelab:

Arquivos de chave

  • js/main.js: arquivo JavaScript principal do aplicativo.
  • service-worker.js: arquivo do service worker do aplicativo.

3. Teste off-line

Antes de fazer qualquer mudança, vamos testar para mostrar que o web app não funciona off-line no momento. Para isso, coloque o computador off-line e recarregue o web app ou, se estiver usando o Chrome:

  1. Abra as Ferramentas para desenvolvedores do Chrome.
  2. Mude para a guia "Aplicativo".
  3. Mude para a seção "Service Workers"
  4. Marque a caixa de seleção "Off-line".
  5. Atualizar a página sem fechar o Chrome DevTools

Guia "Aplicativo" das Ferramentas para desenvolvedores do Chrome aberta para Service Workers com a caixa de seleção "Off-line" marcada

Com o site testado e sem carregar off-line, é hora de adicionar algumas funcionalidades on-line. Desmarque a caixa de seleção "off-line" e siga para a próxima etapa.

4. Interaja off-line

Chegou a hora de adicionar um service worker básico. Isso vai acontecer em duas etapas: registrar o service worker e armazenar recursos em cache.

Registrar um service worker

Já existe um arquivo de service worker vazio. Para garantir que as mudanças apareçam, vamos registrá-lo no aplicativo. Para fazer isso, adicione o código abaixo à parte de cima de js/main.js:

// Register the service worker
if ('serviceWorker' in navigator) {
  // Wait for the 'load' event to not block other work
  window.addEventListener('load', async () => {
    // Try to register the service worker.
    try {
      // Capture the registration for later use, if needed
      let reg;

      // Use ES Module version of our Service Worker in development
      if (import.meta.env?.DEV) {
        reg = await navigator.serviceWorker.register('/service-worker.js', {
          type: 'module',
        });
      } else {
        // In production, use the normal service worker registration
        reg = await navigator.serviceWorker.register('/service-worker.js');
      }

      console.log('Service worker registered! 😎', reg);
    } catch (err) {
      console.log('😥 Service worker registration failed: ', err);
    }
  });
}

Explicação

Esse código registra o arquivo vazio do service worker service-worker.js assim que a página é carregada e somente se o site for compatível com service workers.

Pré-cache de recursos

Para que o app da Web funcione off-line, o navegador precisa responder a solicitações de rede e escolher para onde encaminhá-las. Para fazer isso, adicione o seguinte a service-worker.js:

// Choose a cache name
const cacheName = 'cache-v1';
// List the files to precache
const precacheResources = ['/', '/index.html', '/css/style.css', '/js/main.js', '/js/app/editor.js', '/js/lib/actions.js'];

// When the service worker is installing, open the cache and add the precache resources to it
self.addEventListener('install', (event) => {
  console.log('Service worker install event!');
  event.waitUntil(caches.open(cacheName).then((cache) => cache.addAll(precacheResources)));
});

self.addEventListener('activate', (event) => {
  console.log('Service worker activate event!');
});

// When there's an incoming fetch request, try and respond with a precached resource, otherwise fall back to the network
self.addEventListener('fetch', (event) => {
  console.log('Fetch intercepted for:', event.request.url);
  event.respondWith(
    caches.match(event.request).then((cachedResponse) => {
      if (cachedResponse) {
        return cachedResponse;
      }
      return fetch(event.request);
    }),
  );
});

Agora, volte ao navegador, feche a guia de visualização e abra-a novamente. Você vai ver console.logs correspondentes aos diferentes eventos no service worker.

Em seguida, fique off-line de novo e atualize o site. Ele vai carregar mesmo que você esteja off-line.

Explicação

Durante o evento de instalação do service worker, um cache nomeado é aberto usando a API Cache Storage. Os arquivos e rotas especificados em precacheResources são carregados no cache usando o método cache.addAll. Isso é chamado de pré-cache porque armazena em cache preventivamente o conjunto de arquivos durante a instalação, em vez de armazená-los quando são necessários ou solicitados.

Depois que o service worker controla o site, os recursos solicitados passam por ele como um proxy. Cada solicitação aciona um evento de busca que, neste service worker, procura uma correspondência no cache e, se houver uma, responde com o recurso armazenado em cache. Se não houver uma correspondência, o recurso será solicitado normalmente.

O armazenamento em cache permite que o app funcione off-line, evitando solicitações de rede. Agora o app pode responder com um código de status 200 quando estiver off-line.

5. Parabéns!

Você aprendeu a colocar seu web app off-line usando service workers e a API Cache Storage.

O próximo codelab da série é Como trabalhar com o Workbox.