Os service workers são scripts que operam em segundo plano, desempenhando um papel crucial ao fornecer funcionalidades avançadas de cache e outros recursos essenciais para aplicações web contemporâneas.
Esses mecanismos transformam a experiência do usuário, assemelhando-se à fluidez e praticidade dos aplicativos nativos diretamente no navegador web.
Os service workers são, portanto, pilares na construção de Progressive Web Apps (PWAs).
Entendendo os Service Workers
Um service worker é um tipo específico de Web Worker JavaScript, executado em segundo plano e de forma independente da thread JavaScript principal. Essa separação evita bloqueios e garante que a interface do usuário do aplicativo e a interação do usuário permaneçam responsivas, sem atrasos ou interrupções.
Na prática, os service workers atuam como servidores proxy, posicionando-se entre a aplicação web e a rede. Eles têm a capacidade de interceptar requisições e respostas, armazenar recursos em cache e oferecer suporte para acesso offline. Isso resulta em aplicações web mais integradas e fáceis de usar, mesmo quando a conexão com a internet é interrompida.
Aplicações Principais para Service Workers
A versatilidade dos service workers permite seu uso em diversas situações, incluindo:
- PWAs: Os service workers são o motor dos Progressive Web Apps, possibilitando requisições de rede customizadas, notificações push, funcionalidade offline e carregamento ágil.
- Cache: Eles armazenam ativos do aplicativo, como imagens, código JavaScript e arquivos CSS, no cache do navegador. Isso possibilita que o navegador recupere esses elementos diretamente do cache, ao invés de solicitá-los repetidamente do servidor. O resultado é um carregamento mais rápido do conteúdo, especialmente útil em conexões de internet lentas ou instáveis.
- Sincronização em Segundo Plano: Os service workers podem sincronizar dados e realizar outras tarefas em segundo plano, mesmo quando o usuário não está interagindo ativamente com o aplicativo ou quando ele não está aberto no navegador.
Integrando Service Workers em Aplicações Next.js
Antes de nos aprofundarmos no código, é importante compreender o ciclo de vida de um service worker, que se divide em duas fases principais: registro e ativação.
Na primeira fase, o navegador registra o service worker. Veja um exemplo básico:
const registrarServiceWorker = async () => { if ("serviceWorker" in navigator) { registro = await navigator.serviceWorker.register("/sw.js"); } }; registrarServiceWorker();
Este código verifica se o navegador suporta service workers, o que é comum em todos os navegadores modernos. Caso exista suporte, o código registrará um service worker, localizado no caminho de arquivo especificado.
Na fase de ativação, é necessário instalar e ativar o service worker, escutando os eventos de instalação e ativação por meio de ouvintes de eventos JavaScript. Veja como realizar essa operação:
registro.addEventListener("install", () => { console.log("Service worker instalado"); }); registro.addEventListener("activate", () => { console.log("Service worker ativado"); });
Este código deve ser inserido logo após o registro do service worker e executado assim que o registro for concluído.
O código completo deste projeto pode ser encontrado no repositório GitHub.
Criando um Projeto Next.js
Para começar, utilize o seguinte comando para criar a estrutura básica de um projeto Next.js localmente:
npx create-next-app next-project
A adição de um service worker a um aplicativo Next.js envolve os seguintes passos:
- Registrar o service worker no escopo global do ambiente.
- Criar um arquivo JavaScript para o service worker no diretório público.
Adicionando um Service Worker
Primeiramente, registre o service worker. Modifique o arquivo src/pages/_app.js como descrito abaixo. A inclusão do código neste arquivo garante que o service worker seja registrado assim que o aplicativo for carregado e que tenha acesso a todos os recursos do aplicativo.
import { useEffect } from 'react'; export default function App({ Component, pageProps }) { useEffect(() => { if ('serviceWorker' in navigator) { navigator.serviceWorker .register('/service-worker.js', { scope: "https://www.makeuseof.com/" }) .then((registration) => { console.log( 'Service worker registrado com sucesso. Escopo:', registration.scope ); }) .catch((error) => { console.error('Falha no registro do service worker:', error); }); } }, []); return <Component {...pageProps} />; }
O hook useEffect é acionado quando o componente é montado. Similar ao exemplo anterior, o código primeiro verifica se o navegador do usuário oferece suporte a service workers.
Se o suporte existir, ele registra o script do service worker, localizado no caminho de arquivo especificado, e define seu escopo como “/”. Isso significa que o service worker tem controle sobre todos os recursos do aplicativo. É possível definir um escopo mais específico, como “/produtos”, se necessário.
Caso o registro seja bem-sucedido, uma mensagem de confirmação, juntamente com seu escopo, será registrada. Se ocorrer um erro durante o processo, o código irá detectá-lo e exibir uma mensagem de erro.
Instalando e Ativando o Service Worker
Adicione o seguinte código a um novo arquivo, public/service-worker.js.
const eventoInstalar = () => { self.addEventListener('install', () => { console.log('service worker instalado!!!!'); }); }; eventoInstalar(); const eventoAtivar = () => { self.addEventListener('activate', () => { console.log('service worker ativado!!!'); }); }; eventoAtivar();
Para confirmar o registro, instalação e ativação bem-sucedida do service worker, inicie o servidor de desenvolvimento e abra o aplicativo no navegador.
npm run dev
Abra a janela Ferramentas do desenvolvedor do Chrome (ou equivalente em seu navegador) e acesse a aba “Aplicativo”. Na seção “Service Workers”, você poderá ver o service worker que você registrou.
Com o service worker registrado, instalado e ativado com sucesso, você pode começar a implementar funcionalidades como cache, sincronização em segundo plano ou envio de notificações push.
Armazenando Recursos em Cache com Service Workers
O armazenamento em cache dos ativos do aplicativo no dispositivo do usuário pode otimizar o desempenho, permitindo acesso mais rápido aos recursos, especialmente em situações com conexões de internet instáveis.
Para armazenar os ativos do aplicativo em cache, insira o código a seguir no arquivo service-worker.js.
const nomeCache="teste-cache"; self.addEventListener('fetch', (event) => { event.respondWith( caches.match(event.request).then((respostaCache) => { return respostaCache || fetch(event.request).then((resposta) => { return caches.open(nomeCache).then((cache) => { cache.put(event.request, resposta.clone()); return resposta; }); }); }) ); });
Ao acessar a página inicial pela primeira vez, esse código verifica se existe uma resposta em cache para a requisição. Caso a resposta em cache seja encontrada, o service worker a retorna ao cliente.
Caso a resposta em cache não exista, o service worker busca o recurso do servidor através da rede, fornecendo a resposta ao cliente e armazenando-a em cache para requisições futuras.
Para visualizar os ativos armazenados em cache, abra a aba “Aplicativo” nas ferramentas do desenvolvedor. Na seção “Armazenamento em cache”, você deverá encontrar uma lista dos ativos que foram armazenados em cache. É possível também marcar a opção “Offline” na seção “Service Worker” e recarregar a página para simular uma experiência offline.
Agora, após visitar a página inicial, o navegador utilizará os recursos armazenados em cache, ao invés de solicitar dados da rede.
Utilizando Service Workers para Otimizar o Desempenho
Os service workers representam uma ferramenta eficaz para aprimorar o desempenho de aplicações Next.js. Através do armazenamento em cache de recursos, interceptação de requisições e oferecimento de suporte offline, a experiência do usuário é significativamente melhorada.
É importante salientar, no entanto, que a implementação e gestão de service workers podem apresentar certa complexidade. É crucial analisar cuidadosamente os potenciais benefícios e desvantagens antes de decidir utilizá-los.