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.
Medida
Antes de adicionar otimizações, é sempre bom analisar 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 .
Na nova guia aberta, verifique como o site se comporta ao ficar off-line:
- Pressione "Control + Shift + J" (ou "Command + Option + J" no Mac) para abrir o DevTools.
- Clique na guia Rede.
- Abra o Chrome DevTools e selecione o painel "Network".
- Na lista suspensa Limitação, selecione Off-line.
- No app de demonstração, digite uma consulta de pesquisa e clique no botão Search.
A página de erro padrão do navegador é mostrada:
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 sempre possa ser armazenado em cache no evento install
do service worker.
Normalmente, é necessário instruir o Workbox para adicionar esse arquivo à lista de pré-cache no momento da compilação, integrando a biblioteca com a ferramenta de compilação de sua escolha (por exemplo, webpack ou gulp).
Para simplificar, já fizemos isso para você. O código a seguir 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:
- Para ver a fonte, pressione Ver fonte.
- Adicione o código abaixo à 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 "Apenas na rede" que será aplicada a todas as solicitações.
- Declara um gerenciador de erro global chamando
workbox.routing.setCatchHandler()
para gerenciar solicitações com falha. Quando as solicitações são para documentos, uma página HTML off-line substituta é retornada.
Para testar essa funcionalidade:
- Volte para a outra guia que está executando seu app.
- Defina a lista suspensa Limitação novamente como On-line.
- Pressione o botão Voltar do Chrome para voltar à página de pesquisa.
- Confira se a caixa de seleção Desativar cache está desativada no DevTools.
- Mantenha o botão Atualizar do Chrome pressionado e selecione Esvaziar cache e recarregar o hardware para garantir que o service worker seja atualizado.
- Defina a lista suspensa Limitação novamente como Off-line.
- Digite uma consulta de pesquisa e clique no botão Pesquisar novamente.
A página HTML substituta é exibida:
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 inferior:
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 Assinar notificações, a função
requestNotificationPermission()
é chamada e chamaNotification.requestPermission()
para mostrar a solicitação de permissão padrão do navegador. A promessa é resolvida com a permissão escolhida pelo usuário, que pode sergranted
,denied
oudefault
. - Transmite a permissão resolvida para
showOfflineText()
para mostrar o texto apropriado ao usuário.
Manter consultas off-line e tentar novamente quando estiver on-line novamente
Em seguida, implemente a Sincronização em segundo plano da caixa de trabalho para manter as consultas off-line, de modo que elas possam ser repetidas quando o navegador detectar que a conectividade retornou.
- Abra o arquivo
public/sw.js
para editar. - Adicione o código abaixo 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}¬ification=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 possam ser repetidas mais tarde. Essas solicitações serão mantidas no IndexedDB.maxRetentionTime
indica por quanto tempo uma solicitação pode ser repetida. Nesse caso, escolhemos 60 minutos (depois dos quais ele será descartado).onSync
é a parte mais importante desse código. Esse callback será chamado quando a conexão for restabelecida para que as solicitações na fila sejam recuperadas e, em seguida, buscadas na rede.- A resposta da rede é adicionada ao cache do
offline-search-responses
, anexando o parâmetro de consulta¬ification=true
, para que essa entrada de cache possa ser capturada 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 código abaixo à 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 instrui o Workbox a 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 a seguir à 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 eles possam ser disponibilizados 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 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
- Volte para a outra guia que está executando seu app.
- Defina a lista suspensa Limitação novamente como On-line.
- Pressione o botão Voltar do Chrome para voltar à página de pesquisa.
- Mantenha o botão Atualizar do Chrome pressionado e selecione Esvaziar cache e recarregar o hardware para garantir que o service worker seja atualizado.
- Defina a lista suspensa Limitação novamente como Off-line.
- Digite uma consulta de pesquisa e clique no botão Pesquisar novamente.
- Clique em Inscrever-se para receber notificações.
- Quando o Chrome perguntar se você quer conceder permissão ao app para enviar notificações, clique em Permitir.
- Digite outra consulta de pesquisa e clique no botão Pesquisar novamente.
- Defina a lista suspensa Limitação novamente como On-line.
Quando a conexão for restabelecida, uma notificação será exibida:
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 Workbox para garantir que as consultas do usuário off-line não sejam perdidas e 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 redes sociais etc.