Como indexar suas páginas compatíveis com o modo off-line com a API Content Indexing

Como ativar service workers para informar aos navegadores quais páginas funcionam off-line

O que é a API Content Indexing?

Usar um Progressive Web App significa ter acesso a informações importantes para as pessoas, como imagens, vídeos, artigos e muito mais, independentemente do estado atual da sua conexão de rede. Tecnologias como service workers, a API Cache Storage e o IndexedDB fornecem a você os elementos básicos para armazenar e fornecer dados quando as pessoas interagem diretamente com um PWA. Mas a criação de um PWA de alta qualidade que prioriza o modo off-line é apenas parte da história. Se as pessoas não perceberem que o conteúdo de um aplicativo da Web está disponível enquanto estiverem off-line, elas não aproveitarão ao máximo o trabalho que você fez para implementar essa funcionalidade.

Isso é um problema de descoberta. Como o PWA pode informar os usuários sobre o conteúdo off-line para que eles possam descobrir e visualizar o que está disponível? A API Content Indexing é uma solução para esse problema. A parte voltada para o desenvolvedor dessa solução é uma extensão para service workers, que permite aos desenvolvedores adicionar URLs e metadados de páginas com capacidade off-line a um índice local mantido pelo navegador. Essa melhoria está disponível no Chrome 84 e posterior.

Depois que o índice for preenchido com o conteúdo do PWA, bem como de qualquer outro PWA instalado, ele será exibido pelo navegador, conforme mostrado abaixo.

Captura de tela do item de menu "Downloads" na página "Nova guia" do Chrome.
Primeiro, selecione o item de menu Downloads na página "Nova guia" do Chrome.
Mídia e artigos que foram adicionados ao índice.
As mídias e artigos que foram adicionados ao índice serão mostrados na seção Artigos para você.

Além disso, o Chrome pode recomendar conteúdo de forma proativa quando detectar que um usuário está off-line.

A API Content Indexing não é uma maneira alternativa de armazenar conteúdo em cache. É uma forma de fornecer metadados sobre páginas que já estão armazenadas em cache pelo service worker para que o navegador possa exibir essas páginas quando as pessoas quiserem visualizá-las. A API Content Indexing ajuda na capacidade de descoberta de páginas armazenadas em cache.

Confira na prática

A melhor maneira de conhecer a API Content Indexing é testar um aplicativo de exemplo.

  1. Verifique se você está usando um navegador e uma plataforma compatíveis. No momento, isso está limitado ao Chrome 84 ou versões mais recentes no Android. Acesse about://version para ver qual versão do Chrome você está executando.
  2. Acesse https://contentindex.dev (link em inglês)
  3. Clique no botão + ao lado de um ou mais itens da lista.
  4. (Opcional) Desative a conexão Wi-Fi e de dados móveis do dispositivo ou ative o modo avião para simular o uso do navegador off-line.
  5. Escolha Downloads no menu do Google Chrome e mude para a guia Artigos para você.
  6. Navegue pelo conteúdo que você salvou.

Confira o código-fonte do aplicativo de exemplo no GitHub (link em inglês).

Outro aplicativo de exemplo, o PWA do Scrapbook, ilustra o uso da API Content Indexing com a API Web Share Target. O código demonstra uma técnica para manter a API Content Indexing em sincronia com itens armazenados por um app da Web usando a API Cache Storage.

Como usar a API

Para usar a API, seu app precisa ter um service worker e URLs navegáveis off-line. Se o seu app da Web não tiver um service worker, as bibliotecas da caixa de trabalho poderão simplificar a criação de um.

Que tipo de URLs podem ser indexados como compatíveis com o modo off-line?

A API oferece suporte à indexação de URLs correspondentes a documentos HTML. Um URL para um arquivo de mídia armazenado em cache, por exemplo, não pode ser indexado diretamente. Em vez disso, é necessário fornecer um URL para uma página que exibe mídia e que funciona off-line.

Um padrão recomendado é criar uma página HTML "visualizador" que aceite o URL de mídia subjacente como um parâmetro de consulta e, em seguida, exiba o conteúdo do arquivo, possivelmente com mais controles ou conteúdo na página.

Os apps da Web só podem adicionar URLs ao índice de conteúdo que estão sob o escopo do service worker atual. Em outras palavras, um aplicativo da Web não poderia adicionar um URL pertencente a um domínio completamente diferente no índice de conteúdo.

Visão geral

A API Content Indexing é compatível com três operações: adição, listagem e remoção de metadados. Esses métodos são expostos de uma nova propriedade, index, que foi adicionada à interface ServiceWorkerRegistration.

A primeira etapa para indexar o conteúdo é fazer uma referência ao ServiceWorkerRegistration atual. Usar navigator.serviceWorker.ready é a maneira mais direta:

const registration = await navigator.serviceWorker.ready;

// Remember to feature-detect before using the API:
if ('index' in registration) {
  // Your Content Indexing API code goes here!
}

Se você estiver fazendo chamadas para a API Content Indexing de dentro de um service worker, em vez de dentro de uma página da Web, poderá consultar o ServiceWorkerRegistration diretamente via registration. Ele já estará definido como parte do parâmetro ServiceWorkerGlobalScope.

Adicionando ao índice

Use o método add() para indexar URLs e metadados associados. Você decide quando os itens são adicionados ao índice. Você pode querer adicionar ao índice em resposta a uma entrada, como clicar em um botão "Salvar off-line". Ou você pode adicionar itens automaticamente sempre que os dados em cache forem atualizados com um mecanismo como a sincronização periódica em segundo plano.

await registration.index.add({
  // Required; set to something unique within your web app.
  id: 'article-123',

  // Required; url needs to be an offline-capable HTML page.
  url: '/articles/123',

  // Required; used in user-visible lists of content.
  title: 'Article title',

  // Required; used in user-visible lists of content.
  description: 'Amazing article about things!',

  // Required; used in user-visible lists of content.
  icons: [{
    src: '/img/article-123.png',
    sizes: '64x64',
    type: 'image/png',
  }],

  // Optional; valid categories are currently:
  // 'homepage', 'article', 'video', 'audio', or '' (default).
  category: 'article',
});

Adicionar uma entrada afeta apenas o índice de conteúdo. Isso não acrescenta nada ao cache.

Caso extremo: chamar add() no contexto de window se os ícones dependerem de um gerenciador fetch

Quando você chama add(), o Chrome solicita o URL de cada ícone para garantir que ele tenha uma cópia do ícone para usar ao exibir uma lista de conteúdo indexado.

  • Se você chamar add() do contexto window (em outras palavras, da sua página da Web), essa solicitação acionará um evento fetch no service worker.

  • Se você chamar add() no seu service worker, talvez dentro de outro manipulador de eventos, a solicitação não acionará o gerenciador fetch do service worker. Os ícones serão buscados diretamente, sem o envolvimento de um service worker. Lembre-se se os ícones dependem do gerenciador fetch, talvez porque eles existam apenas no cache local e não na rede. Se isso acontecer, chame add() apenas no contexto window.

Como listar o conteúdo do índice

O método getAll() retorna uma promessa para uma lista iterável de entradas indexadas e os respectivos metadados. As entradas retornadas vão conter todos os dados salvos com add().

const entries = await registration.index.getAll();
for (const entry of entries) {
  // entry.id, entry.launchUrl, etc. are all exposed.
}

Remover itens do índice

Para remover um item do índice, chame delete() com o id do item a ser removido:

await registration.index.delete('article-123');

Chamar delete() afeta apenas o índice. Ele não exclui nada do cache.

Processar um evento de exclusão de usuário

Quando o navegador exibe o conteúdo indexado, ele pode incluir a própria interface do usuário com um item de menu Excluir. Assim, as pessoas podem indicar que concluíram o conteúdo indexado anteriormente. Esta é a aparência da interface de exclusão no Chrome 80:

O item de menu "Excluir".

Quando alguém selecionar esse item de menu, o service worker do seu app da Web receberá um evento contentdelete. Embora o processamento desse evento seja opcional, ele oferece uma chance para o service worker "limpar" o conteúdo, como arquivos de mídia armazenados em cache localmente, que alguém indicou que já terminou.

Não é necessário chamar registration.index.delete() dentro do gerenciador contentdelete. Se o evento foi disparado, a exclusão do índice relevante já foi realizada pelo navegador.

self.addEventListener('contentdelete', (event) => {
  // event.id will correspond to the id value used
  // when the indexed content was added.
  // Use that value to determine what content, if any,
  // to delete from wherever your app stores it—usually
  // the Cache Storage API or perhaps IndexedDB.
});

Feedback sobre o design da API

Há algo estranho na API ou que não funciona como esperado? Ou há peças faltando que você precisa para implementar sua ideia?

Registre um problema no repositório de explicação da API Content Indexing do GitHub (em inglês) ou adicione suas ideias a um problema existente.

Problemas com a implementação?

Você encontrou um bug na implementação do Chrome?

Registre um bug em https://new.crbug.com (link em inglês). Inclua o máximo de detalhes possível, instruções simples para reprodução e defina Componentes como Blink>ContentIndexing.

Pretende usar a API?

Pretende usar a API Content Indexing em seu app da Web? Seu suporte público ajuda o Chrome a priorizar recursos e mostra a outros fornecedores de navegador a importância de oferecer suporte a eles.

Quais são as implicações de segurança e privacidade da indexação de conteúdo?

Confira as respostas fornecidas em resposta ao questionário de segurança e privacidade do W3C. Se você tiver outras dúvidas, inicie uma discussão no repositório do GitHub do projeto.

Imagem principal por Maksym Kaharlytskyi no Unsplash.