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
Na nova guia aberta, verifique como o site se comporta quando fica 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 Pesquisar.
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 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:
- Para conferir a fonte, pressione Ver código-fonte.
- 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:
- Volte para a outra guia que está executando o app.
- Defina a lista suspensa Limitação novamente como On-line.
- Pressione o botão Voltar do Chrome para retornar à página de pesquisa.
- Verifique se a caixa de seleção Desativar cache no DevTools está desativada.
- 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.
- Defina a lista suspensa Limitação novamente como Off-line.
- Digite uma consulta e clique no botão Pesquisar novamente.
A página HTML reserva é 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 inscrever-se para receber notificações, a função
requestNotificationPermission()
é chamada, que chamaNotification.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 sergranted
,denied
oudefault
. - 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.
- 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 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¬ification=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
- Volte para a outra guia que está executando o app.
- Defina a lista suspensa Limitação novamente como On-line.
- Pressione o botão Voltar do Chrome para retornar à página de pesquisa.
- 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.
- 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 pergunta se você deseja conceder ao app permissão 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 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.