Os aplicativos da web progressivos são uma inovação do desenvolvimento da web moderno, combinando a onipresença dos navegadores da web com a riqueza dos aplicativos nativos. Recursos especializados, como service workers, aumentam a complexidade do desenvolvimento em comparação com uma interface de usuário da Web típica, mas fornecem um enorme benefício em troca: recursos nativos entre dispositivos, fornecidos em um navegador da Web.
Recursos de aplicativos da web progressivos
Se você considerar a diferença entre um aplicativo típico de navegador da web e um aplicativo instalado em um laptop ou telefone celular, terá uma noção da lacuna que os aplicativos da web progressivos preenchem. Uma característica definidora dos aplicativos instalados é que eles são executados no dispositivo quando não há conexão de rede. Os aplicativos da web progressivos oferecem suporte a funcionalidades off-line semelhantes no navegador.
Ao contrário dos aplicativos web baseados em navegador, os aplicativos web progressivos são altamente dependentes do tipo de aplicativo: os recursos do aplicativo desempenham um papel importante na determinação de como o PWA é implementado.
As características comuns de aplicativos da web progressivos são:
- Funcionalidade off-line
- Funcionalidade em segundo plano, incluindo sincronização
- “Instalação” da página inicial
- Notificações e alertas push, inclusive quando o aplicativo não está em execução
- Cache agressivo (uma estratégia para combater problemas intermitentes de rede)
- Layouts entre dispositivos/responsivos/primeiros dispositivos móveis
- Pode ser marcado e compartilhado por meio de um link
Um bom caso de uso para um aplicativo da web progressivo é a transição de um aplicativo implantado na web para implementar recursos do PWA, como funcionalidade offline. O Google Docs é um exemplo de aplicativo baseado em navegador que oferece suporte ao “modo off-line” quando a rede não está disponível. Essencialmente, o aplicativo pode salvar tudo localmente no navegador e sincronizar tudo com o back-end quando o navegador voltar a ficar online.
É claro que sincronizar partes distribuídas de um aplicativo é inerentemente complicado. O Google Docs é um grande empreendimento arquitetônico, mas um aplicativo mais básico poderia ser muito mais simples. Os requisitos do aplicativo determinarão o quão envolvente deve ser a implementação do PWA.
Agora que você tem uma ideia do que os aplicativos da web progressivos podem fazer por você, vamos ver como eles funcionam.
Instalando aplicativos da web progressivos
Uma característica distintiva dos aplicativos da web progressivos é que eles podem ser “instalados” mesmo que sejam executados no navegador. No front end, você coloca um link na página inicial do dispositivo que inicia o site no navegador.
A instalação é feita através de um manifest.json
arquivo, que descreve ao navegador os recursos do aplicativo e seu ícone na página inicial. Aqui está um exemplo de um manifesto simples:
{
"name": "My PWA App",
"short_name": "My PWA",
"icons": (
{
"src": "icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
}
),
"start_url": "https://www.infoworld.com/",
"display": "standalone",
"theme_color": "#ffffff"
}
Se o navegador encontrar esse arquivo no diretório raiz e o arquivo for válido, ele oferecerá a adição de um link para a página inicial.
Trabalhadores de serviço
Os service workers são o principal meio de entrega de recursos do PWA. O navigator.serviceWorker
object dá acesso à API do Service Worker. Está disponível apenas em um contexto seguro (HTTPS). Um service worker é semelhante a um thread de trabalho, mas tem um ciclo de vida mais longo e menos acesso ao DOM e às APIs do navegador.
Pense em um service worker como um contexto isolado que pode interagir com seu thread principal (e com outros trabalhadores) por meio de mensagens e eventos. Ele pode responder a esses eventos, executar solicitações de rede, responder a chamadas push e armazenar coisas com a API Cache ou com IndexedDB
. Um service worker só pode atuar na UI por meio de mensagens de volta ao thread principal. De certa forma, um service worker é um middleware proxy executado no navegador.
Os service workers têm um ciclo de vida único. Condições específicas determinam quando serão encerrados. Eles podem executar e apresentar notificações ao usuário com base em atualizações push, mesmo depois que a página que os gerou for fechada. O ciclo de vida do service worker oferece uma boa visão geral. Você também pode encontrar informações específicas do navegador sobre a rescisão de prestadores de serviço; por exemplo, no Chrome.
Eventos do trabalhador de serviço
Essencialmente, os service workers são manipuladores de eventos assíncronos. Eles respondem a eventos da IU ou do back-end. Ao construí-los, você deve planejar que seu contexto seja apagado entre os eventos – você não pode salvar o estado em variáveis locais para compartilhar entre os eventos; em vez disso, você usa o cache ou um banco de dados. Aqui estão todos os eventos aos quais um service worker pode responder:
- instalar: esse evento é acionado uma vez quando o service worker é instalado pela primeira vez. É frequentemente usado para pré-armazenar em cache ativos como arquivos HTML, CSS e JavaScript para permitir o funcionamento offline.
- ativar: este evento é acionado depois que um service worker se torna ativo. Este é um bom lugar para limpar caches de versões anteriores do service worker ou executar qualquer tarefa que precise ser executada quando o service worker assume o controle dos clientes (páginas da web controladas).
- buscar: Este evento é acionado sempre que uma página controlada faz uma solicitação à rede. Isso permite que o service worker atue como um intermediário invisível para a página principal, interceptando solicitações e potencialmente modificando-as para servir uma versão em cache ou tratá-la inteiramente.
- sincronizar: esse evento é acionado em intervalos definidos pelo navegador quando a conexão de rede está estável. É frequentemente usado para sincronizar alterações de dados feitas offline com o servidor. A API Sync ajuda a automatizar a tentativa de solicitações quando a rede está disponível.
- empurrar: este evento é acionado quando o service worker recebe uma notificação push de um servidor. Ele permite que o service worker manipule e exiba a notificação ao usuário mesmo se a página da web estiver fechada.
- clique de notificação: esse evento é acionado quando o usuário clica em uma notificação push exibida. Você pode usar esse evento para lidar com a interação de notificação e potencialmente direcionar o usuário para uma página específica em seu PWA.
- erro: esse evento pode ser acionado em diversas situações em que o service worker encontra um erro durante sua operação. Você pode usar esse evento para fins de registro ou depuração.
- transmitir e postar mensagens: são eventos gerados especificamente pelo seu código JavaScript no thread principal. Eles são usados para transmitir dados aos seus prestadores de serviço.
Junto com esses eventos, os service workers têm acesso a diversas APIs:
- Banco de dados indexado: um banco de dados robusto de armazenamento de objetos que oferece suporte a consultas. Ele reside entre instâncias de service workers e é compartilhado com o thread principal.
- API de cache: a API Cache facilita a captura de objetos de solicitação e o armazenamento de suas respostas. Combinado com o
fetch
Nesse caso, a API Cache facilita o armazenamento em cache de respostas de forma transparente (a partir da visualização do thread principal) para o modo offline. O MDN possui uma boa descrição de possíveis estratégias de cache. - APIs de busca e WebSocket: embora o service worker não tenha acesso ao DOM, ele tem acesso total à rede por meio das APIs Fetch e WebSocket.
- Geolocalização: Há uma discussão contínua sobre como expor os prestadores de serviços à geolocalização e apoiar a geolocalização nos prestadores de serviços.
Exemplo de trabalhador de serviço
Um service worker sempre começa sendo carregado em um arquivo JavaScript com o navigator.serviceWorker
objeto, assim:
const subscription = await navigator.serviceWorker.register('service-worker.js');
As assinaturas de eventos acontecem em service-worker.js
. Por exemplo, para observar um fetch
evento e usar a API de cache, você poderia fazer algo assim:
self.addEventListener('fetch', (event) => {
const request = event.request;
const url = new URL(request.url);
// Try serving assets from cache first
event.respondWith(
caches.match(request)
.then((cachedResponse) => {
// If found in cache, return the cached response
if (cachedResponse) {
return cachedResponse;
}
// If not in cache, fetch from network
return fetch(request)
.then((response) => {
// Clone the response for potential caching
const responseClone = response.clone();
// Cache the new response for future requests
caches.open('my-cache')
.then((cache) => {
cache.put(request, responseClone);
});
return response;
});
})
);
});
Quando o service worker é carregado, self
irá se referir a ele. O addEventListener
O método permite observar vários eventos. Dentro de fetch
caso, você pode usar a API Cache para verificar se o URL de solicitação fornecido já está armazenado em cache; em caso afirmativo, você o enviará de volta. Se o URL for novo, você faz sua solicitação ao servidor e armazena a resposta em cache. Observe que a API Cache elimina grande parte da complexidade na determinação do que é ou não a mesma solicitação. Usar o service worker torna tudo isso transparente para o thread principal.
Conclusão
Os aplicativos da web progressivos permitem que você entregue seu aplicativo em um navegador e ofereçam recursos que você não encontrará em um aplicativo típico baseado em navegador. Por outro lado, você precisa lidar com mais complexidade ao desenvolver aplicativos da web progressivos. A maioria das coisas nativas que você pode fazer com um aplicativo da web progressivo envolve service workers, que exigem mais trabalho do que fazer a mesma coisa em um aplicativo nativo usando um sistema operacional como Android ou macOS.
Usar técnicas de PWA para obter a mesma funcionalidade em várias plataformas de destino dentro do navegador é menos trabalhoso do que reimplementar a funcionalidade em várias plataformas. Com um aplicativo da web progressivo, você só precisa criar e manter uma única base de código e começar a trabalhar com padrões de navegador familiares.