Como criar experiências de pesquisa resilientes com o Workbox

Este codelab mostra como implementar uma experiência de pesquisa resiliente com o Workbox. O app de demonstração usado contém uma caixa de pesquisa que chama um endpoint do servidor e redireciona o usuário para uma página HTML básica.

Medir

Antes de adicionar otimizações, é sempre uma boa ideia analisar primeiro o estado atual do aplicativo.

  • Clique em Remixar para editar para tornar o projeto editável.
  • Para visualizar o site, pressione Ver app. Em seguida, pressione Tela cheia tela cheia

Na nova guia aberta, verifique como o site se comporta quando fica off-line:

  1. Pressione "Control+Shift+J" (ou "Command+Option+J" no Mac) para abrir o DevTools.
  2. Clique na guia Rede.
  3. Abra o Chrome DevTools e selecione o painel Network.
  4. Na lista suspensa "Limitação, selecione Off-line.
  5. No app de demonstração, digite uma consulta de pesquisa e clique no botão Pesquisar.

A página de erro padrão do navegador é mostrada:

Uma captura de tela da UX off-line padrão no navegador.

Fornecer uma resposta substituta

O service worker contém o código para adicionar a página off-line à lista de pré-cache, para que ela sempre possa ser armazenada em cache no evento install do service worker.

Normalmente, é necessário instruir o Workbox a adicionar esse arquivo à lista de pré-cache no momento da criação, integrando a biblioteca com a ferramenta de criação de sua preferência (por exemplo, webpack ou gulp).

Para simplificar, já fizemos isso para você. O código abaixo em public/sw.js faz isso:

const FALLBACK_HTML_URL = '/index_offline.html';

workbox.precaching.precacheAndRoute([FALLBACK_HTML_URL]);

Em seguida, adicione o código para usar a página off-line como uma resposta substituta:

  1. Para conferir a fonte, pressione Ver código-fonte.
  2. Adicione o seguinte código à parte de baixo de public/sw.js:
workbox.routing.setDefaultHandler(new workbox.strategies.NetworkOnly());

workbox.routing.setCatchHandler(({event}) => {
  switch (event.request.destination) {
    case 'document':
      return caches.match(FALLBACK_HTML_URL);
      break;
    default:
      return Response.error();
  }
});

O código realiza as ações a seguir:

  • Define uma estratégia padrão para somente rede que será aplicada a todas as solicitações.
  • Declara um gerenciador de erros global chamando workbox.routing.setCatchHandler() para gerenciar solicitações com falha. Quando as solicitações forem para documentos, uma página HTML off-line substituta será retornada.

Para testar essa funcionalidade:

  1. Volte para a outra guia que está executando o app.
  2. Defina a lista suspensa Limitação novamente como On-line.
  3. Pressione o botão Voltar do Chrome para retornar à página de pesquisa.
  4. Verifique se a caixa de seleção Desativar cache no DevTools está desativada.
  5. Toque e mantenha pressionado o botão Atualizar do Chrome e selecione Cache vazio e atualização forçada para garantir que o service worker seja atualizado.
  6. Defina a lista suspensa Limitação novamente como Off-line.
  7. Digite uma consulta e clique no botão Pesquisar novamente.

A página HTML reserva é mostrada:

Uma captura de tela da UX off-line personalizada no navegador.

Solicitar permissão de notificações

Para simplificar, a página off-line em views/index_offline.html já contém o código para solicitar permissões de notificação em um bloco de script na parte de baixo:

function requestNotificationPermission(event) {
  event.preventDefault();

  Notification.requestPermission().then(function (result) {
    showOfflineText(result);
  });
}

O código realiza as ações a seguir:

  • Quando o usuário clica em inscrever-se para receber notificações, a função requestNotificationPermission() é chamada, que chama Notification.requestPermission(), para mostrar a solicitação de permissão do navegador padrão. A promessa é resolvida com a permissão escolhida pelo usuário, que pode ser granted, denied ou default.
  • Transmite a permissão resolvida ao showOfflineText() para mostrar o texto adequado ao usuário.

Manter consultas off-line e tentar novamente quando estiver on-line

Em seguida, implemente a Sincronização em segundo plano do Workbox para manter as consultas off-line. Assim, elas poderão ser repetidas quando o navegador detectar que a conectividade foi retornada.

  1. Abra public/sw.js para edição.
  2. Adicione o seguinte código ao final do arquivo:
const bgSyncPlugin = new workbox.backgroundSync.Plugin('offlineQueryQueue', {
  maxRetentionTime: 60,
  onSync: async ({queue}) => {
    let entry;
    while ((entry = await queue.shiftRequest())) {
      try {
        const response = await fetch(entry.request);
        const cache = await caches.open('offline-search-responses');
        const offlineUrl = `${entry.request.url}&notification=true`;
        cache.put(offlineUrl, response);
        showNotification(offlineUrl);
      } catch (error) {
        await this.unshiftRequest(entry);
        throw error;
      }
    }
  },
});

O código realiza as ações a seguir:

  • workbox.backgroundSync.Plugin contém a lógica para adicionar solicitações com falha a uma fila para que elas possam ser repetidas mais tarde. Essas solicitações serão mantidas no IndexedDB.
  • maxRetentionTime indica por quanto tempo uma solicitação pode ser repetida. Neste caso, escolhemos 60 minutos (depois disso, eles serão descartados).
  • onSync é a parte mais importante do código. Esse callback será chamado quando a conexão voltar para que as solicitações na fila sejam recuperadas e, em seguida, recuperadas na rede.
  • A resposta da rede é adicionada ao cache offline-search-responses, anexando o parâmetro de consulta &notification=true, para que essa entrada de cache possa ser recebida quando um usuário clicar na notificação.

Para integrar a sincronização em segundo plano ao seu serviço, defina uma estratégia NetworkOnly para solicitações ao URL de pesquisa (/search_action) e transmita o bgSyncPlugin definido anteriormente. Adicione o seguinte código à parte de baixo de public/sw.js:

const matchSearchUrl = ({url}) => {
  const notificationParam = url.searchParams.get('notification');
  return url.pathname === '/search_action' && !(notificationParam === 'true');
};

workbox.routing.registerRoute(
  matchSearchUrl,
  new workbox.strategies.NetworkOnly({
    plugins: [bgSyncPlugin],
  }),
);

Isso diz ao Workbox para sempre acessar a rede e, quando as solicitações falharem, usar a lógica de sincronização em segundo plano.

Em seguida, adicione o código abaixo à parte de baixo de public/sw.js para definir uma estratégia de armazenamento em cache para solicitações provenientes de notificações. Use uma estratégia CacheFirst para que possam ser veiculados a partir do cache.

const matchNotificationUrl = ({url}) => {
  const notificationParam = url.searchParams.get('notification');
  return (url.pathname === '/search_action' && (notificationParam === 'true'));
};

workbox.routing.registerRoute(matchNotificationUrl,
  new workbox.strategies.CacheFirst({
     cacheName: 'offline-search-responses',
  })
);

Por fim, adicione o código para mostrar as notificações:

function showNotification(notificationUrl) {
  if (Notification.permission) {
     self.registration.showNotification('Your search is ready!', {
        body: 'Click to see you search result',
        icon: '/img/workbox.jpg',
        data: {
           url: notificationUrl
        }
     });
  }
}

self.addEventListener('notificationclick', function(event) {
  event.notification.close();
  event.waitUntil(
     clients.openWindow(event.notification.data.url)
  );
});

Testar o recurso

  1. Volte para a outra guia que está executando o app.
  2. Defina a lista suspensa Limitação novamente como On-line.
  3. Pressione o botão Voltar do Chrome para retornar à página de pesquisa.
  4. Toque e mantenha pressionado o botão Atualizar do Chrome e selecione Cache vazio e atualização forçada para garantir que o service worker seja atualizado.
  5. Defina a lista suspensa Limitação novamente como Off-line.
  6. Digite uma consulta de pesquisa e clique no botão Pesquisar novamente.
  7. Clique em Inscrever-se para receber notificações.
  8. Quando o Chrome pergunta se você deseja conceder ao app permissão para enviar notificações, Clique em Permitir.
  9. Digite outra consulta de pesquisa e clique no botão Pesquisar novamente.
  10. Defina a lista suspensa Limitação novamente como On-line.

Quando a conexão for restabelecida, uma notificação será exibida:

Uma captura de tela do fluxo off-line completo.

Conclusão

O Workbox oferece muitos recursos integrados para tornar seus PWAs mais resilientes e envolventes. Neste codelab, você explorou como implementar a API Background Sync usando a abstração da Workbox para garantir que as consultas de usuários off-line não sejam perdidas e que possam ser repetidas quando a conexão for restabelecida. A demonstração é um app de pesquisa simples, mas você pode usar uma implementação semelhante para cenários e casos de uso mais complexos, incluindo apps de chat, postagem de mensagens em uma rede social etc.