Este codelab mostra como implementar uma experiência de pesquisa resiliente com o Workbox. O app de demonstração usado tem 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 bom analisar o estado atual do aplicativo.
- Clique em Remix to Edit para tornar o projeto editável.
- Para visualizar o site, pressione View App. Em seguida, pressione Fullscreen .
Na nova guia que acabou de abrir, verifique como o site se comporta quando fica off-line:
- Pressione "Control+Shift+J" (ou "Command+Option+J" no Mac) para abrir as Ferramentas do desenvolvedor.
- Clique na guia Rede.
- Abra o Chrome DevTools e selecione o painel "Rede".
- Na lista suspensa "Restrição", selecione Off-line.
- 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:
Fornecer uma resposta substituta
O worker de serviço contém o código para adicionar a página off-line à lista de pré-cache, para que ela possa ser armazenada em cache no evento install
do worker de serviço.
Normalmente, é necessário instruir o Workbox a adicionar esse arquivo à lista de pré-cache no momento da criação, integrando a biblioteca à ferramenta de build escolhida (por exemplo, webpack ou gulp).
Para simplificar, já fizemos isso por 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 alternativa:
- Para conferir a origem, pressione View Source.
- 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 somente de rede padrão 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 são para documentos, uma página HTML off-line alternativa é retornada.
Para testar essa funcionalidade:
- Volte para a outra guia em que o app está sendo executado.
- Defina a lista suspensa Limitação como Online.
- Pressione o botão Voltar do Chrome para voltar à página de pesquisa.
- Verifique se a caixa de seleção Desativar cache no DevTools está desativada.
- Toque e mantenha pressionado o botão Reload do Chrome e selecione Empty cache and hard reload para garantir que o service worker seja atualizado.
- Defina a lista suspensa Limitação como Off-line novamente.
- Digite uma consulta e clique no botão Pesquisar novamente.
A página HTML de substituição é mostrada:
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 Assinar notificações, a função
requestNotificationPermission()
é chamada, o que 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 voltar a ficar on-line
Em seguida, implemente a sincronização em segundo plano do Workbox para manter as consultas off-line, para que elas possam ser repetidas quando o navegador detectar que a conectividade foi restabelecida.
- Abra
public/sw.js
para edição. - 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}¬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 elas possam ser tentadas novamente mais tarde. Essas solicitações serão mantidas na IndexedDB.maxRetentionTime
indica o tempo que uma solicitação pode ser repetida. Neste caso, escolhemos 60 minutos (após esse período, o cookie será descartado).onSync
é a parte mais importante deste código. Esse callback será chamado quando a conexão for restabelecida para que as solicitações enfileiradas sejam recuperadas e extraídas da rede.- A resposta da rede é adicionada ao cache
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 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 informa ao Workbox que ele sempre vai para a rede e, quando as solicitações falharem, use 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 eles possam ser exibidos no 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
- Volte para a outra guia em que o app está sendo executado.
- Defina a lista suspensa Limitação como Online.
- Pressione o botão Voltar do Chrome para voltar à página de pesquisa.
- Toque e mantenha pressionado o botão Reload do Chrome e selecione Empty cache and hard reload para garantir que o service worker seja atualizado.
- Defina a lista suspensa Limitação como Off-line novamente.
- Digite uma consulta 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 e clique no botão Pesquisar novamente.
- Defina a lista suspensa Throttling como Online novamente.
Quando a conexão for restabelecida, uma notificação será mostrada:
Conclusão
O Workbox oferece muitos recursos integrados para tornar seus PWAs mais resilientes e envolventes. Neste codelab, você aprendeu a implementar a API Background Sync usando a abstração do 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 uma rede social etc.