Como gerenciar respostas substitutas

Em determinadas situações, é possível armazenar uma resposta substituta em cache caso o usuário esteja off-line. Implementar um substituto é uma alternativa aos comportamentos de armazenamento em cache que estratégias como priorização da rede ou obsoleto durante a revalidação.

Um substituto é uma resposta genérica de tamanho único que é um marcador de posição melhor do que o que o navegador forneceria por padrão quando uma solicitação falha. Por exemplo:

  • Uma alternativa ao marcador de posição "imagem ausente".
  • Uma alternativa em HTML à página padrão "nenhuma conexão de rede disponível".

Somente página off-line

Se você só precisa fornecer uma página HTML off-line personalizada, mas nada mais, aqui está uma receita básica que você pode seguir:

import {offlineFallback} from 'workbox-recipes';
import {setDefaultHandler} from 'workbox-routing';
import {NetworkOnly} from 'workbox-strategies';

setDefaultHandler(new NetworkOnly());

offlineFallback();

O código acima usa setDefaultHandler para aplicar uma estratégia somente de rede como padrão para todas as rotas. Em seguida, ele executa o roteiro offlineFallback para disponibilizar o substituto off-line caso ocorra um erro. O roteiro presume que o arquivo HTML substituto off-line terá o nome offline.html e será veiculado pela raiz do servidor da Web.

Substitutos abrangentes

Sempre que ocorrer uma falha de rede ou ausência no cache, as estratégias de armazenamento em cache oferecidas pelo workbox-strategies serão rejeitadas de forma consistente. Isso promove o padrão de configuração de um gerenciador "catch" global para lidar com falhas em uma única função de gerenciador, permitindo que você ofereça diferentes substitutos para diferentes valores de request.destination.

O exemplo a seguir usa o roteiro warmStrategyCache de workbox-recipes e define um gerenciador de captura para disponibilizar itens armazenados em cache antecipadamente no cache de tempo de execução. No entanto, os substitutos de armazenamento em cache antecipado podem ser mais adequados para seu aplicativo:

import {warmStrategyCache} from 'workbox-recipes';
import {setDefaultHandler, setCatchHandler} from 'workbox-routing';
import {CacheFirst, StaleWhileRevalidate} from 'workbox-strategies';

// Fallback assets to cache
const FALLBACK_HTML_URL = '/offline.html';
const FALLBACK_IMAGE_URL = '/images/image-not-found.jpg';
const FALLBACK_STRATEGY = new CacheFirst();

// Warm the runtime cache with a list of asset URLs
warmStrategyCache({
  urls: [FALLBACK_HTML_URL, FALLBACK_IMAGE_URL],
  strategy: FALLBACK_STRATEGY,
});

// Use a stale-while-revalidate strategy to handle requests by default.
setDefaultHandler(new StaleWhileRevalidate());

// This "catch" handler is triggered when any of the other routes fail to
// generate a response.
setCatchHandler(async ({request}) => {
  // The warmStrategyCache recipe is used to add the fallback assets ahead of
  // time to the runtime cache, and are served in the event of an error below.
  // Use `event`, `request`, and `url` to figure out how to respond, or
  // use request.destination to match requests for specific resource types.
  switch (request.destination) {
    case 'document':
      return FALLBACK_STRATEGY.handle({event, request: FALLBACK_HTML_URL});

    case 'image':
      return FALLBACK_STRATEGY.handle({event, request: FALLBACK_IMAGE_URL});

    default:
      // If we don't have a fallback, return an error response.
      return Response.error();
  }
});

A seguir, as respostas substitutas são pré-armazenadas em cache usando injectManifest com as ferramentas de build do Workbox e usadas como substitutos no caso de um erro com o método matchPrecache.

import {matchPrecache, precacheAndRoute} from 'workbox-precaching';
import {setDefaultHandler, setCatchHandler} from 'workbox-routing';
import {StaleWhileRevalidate} from 'workbox-strategies';

// Optional: use the injectManifest mode of one of the Workbox
// build tools to precache a list of URLs, including fallbacks.
precacheAndRoute(self.__WB_MANIFEST);

// Use a stale-while-revalidate strategy to handle requests by default.
setDefaultHandler(new StaleWhileRevalidate());

// This "catch" handler is triggered when any of the other routes fail to
// generate a response.
setCatchHandler(async ({request}) => {
  // Fallback assets are precached when the service worker is installed, and are
  // served in the event of an error below. Use `event`, `request`, and `url` to
  // figure out how to respond, or use request.destination to match requests for
  // specific resource types.
  switch (request.destination) {
    case 'document':
      // FALLBACK_HTML_URL must be defined as a precached URL for this to work:
      return matchPrecache(FALLBACK_HTML_URL);

    case 'image':
      // FALLBACK_IMAGE_URL must be defined as a precached URL for this to work:
      return matchPrecache(FALLBACK_IMAGE_URL);

    default:
      // If we don't have a fallback, return an error response.
      return Response.error();
  }
});

Um exemplo de caso de uso para a segunda configuração de substituto é se uma página foi armazenada em cache antecipadamente, mas as imagens (ou outros recursos) solicitados pela página não foram. A página ainda poderá ser lida no cache quando o usuário estiver off-line, mas marcadores substitutos ou recursos alternativos poderão ser fornecidos se ocorrer um erro de rede.

Como aquecer o cache de ambiente de execução

O Workbox mantém caches separados para pré-armazenamento em cache e caches de tempo de execução. Pode haver situações em que você queira armazenar algo em cache antecipadamente sem depender de pré-armazenamento em cache, já que as atualizações no manifesto de pré-cache exigem que você implante um service worker atualizado.

Para preparar o cache do ambiente de execução com recursos, use o roteiro warmStrategyCache de workbox-recipes. Internamente, essa estratégia chama Cache.addAll no evento install de um service worker.

import {warmStrategyCache} from 'workbox-recipes';
import {CacheFirst} from 'workbox-strategies';

// This can be any strategy, CacheFirst used as an example.
const strategy = new CacheFirst();
const urls = [
  '/offline.html',
];

warmStrategyCache({urls, strategy});

Conclusão

Gerenciar respostas substitutas para solicitações com falha exige um pouco de trabalho. No entanto, com um pouco de planejamento, você pode configurar seu app da Web para fornecer algum nível de conteúdo e funcionalidade quando o usuário estiver off-line.