Service Workers: Dicas de desenvolvimento

Recentemente precisamos implementar uma feature em uma das aplicações front-end que temos na Creditas. Parecia simples, colocar notificações utilizando Pusher para informar o usuário que algo aconteceu. Pusher é um PaaS que oferece serviço de notificações de eventos em Real-Time para sua aplicação. Porém analisando a forma como nossos usuários utilizavam a aplicação, encontramos um
Service Workers: Dicas de desenvolvimento

Recentemente precisamos implementar uma feature em uma das aplicações front-end
que temos na Creditas. Parecia simples, colocar notificações utilizando
Pusher para informar o usuário que algo aconteceu.

Pusher é um PaaS que oferece serviço de notificações de
eventos em Real-Time para sua aplicação.

Porém analisando a forma como nossos usuários utilizavam a aplicação,
encontramos um padrão de uso que dificultaria a implementação. Nossos usuários
abriam uma nova aba para cada tarefa que eles precisavam gerenciar. Até ai tudo
bem, o problema é que cada aba no browser é um processo (existem controvérsia)
separado que não compartilha estado entre si. Ao implementar o
Pusher, ele criava uma conexão socket para cada aba, ou
seja, ao ser enviado um evento para um channel no Pusher,
todas as abas iriam escutar e executar a ação ao mesmo tempo. Com certeza essa
não era a experiencia que queríamos, pois existia uma grande chance de algo dar
errado.


Implementação sem Service Workers: Como é possível ver, existe uma conexão
socket para cada aba no browser aberta.

Entendendo o problema e pesquisando soluções encontramos Service Worker como
alternativa. Service Worker faz parte do conjunto de especificações em torno do
HTML5, você pode saber mais na Web Docs da
Mozilla
.

Definição por Matt Gaunt

A service worker is a script that your browser runs in the background, separate from a web page, opening the door to features that don’t need a web page or user interaction. Today, they already include features like push notifications and background sync.

Service Worker não é uma novidade, eu já tinha estudado há uns anos atrás como
solução para processamento em background em aplicativos mobiles. Mas, pela
primeira vez considerei usa-lo para resolver um problema em browser desktop e
não mobile.


Implementação com Service Worker: Neste modelo agora temos um worker conectado
em todas as abas abertas com apenas uma conexão socket aberta.


Vou apresentar um pouco do que aprendi implementando Service Worker no browser
desktop.

Basicamente existem muitas aplicabilidades para Service Worker, podemos receber
push notifications, processos em background, requisições off-line, entre outros.

Service Worker vem sendo bastante explorado em Progressive Web App (PWA) para
oferecer uma experiencia mobile em uma aplicação web. Nesse post da Magnetis
eles explicam um pouco mais sobre PWA e como usando o Service Worker.

Vamos lá, separei alguns pontos interessantes:

Localização do arquivo

Seu Service Worker só será instalado se o arquivo estiver no mesmo nível do
local onde está sendo instalado.

Supondo que você tenha um arquivo index.html que registra o seu Service
Worker localizado na pasta /blog/. Neste caso, a localização do seu arquivo
do Service Worker deve está localizado no mesmo nível /blog/sw.js. Caso
contrario ele não será instalado.

project-with-sw/ ├── home.html └── blog ├── index.html ←Esse
arquivo deve registrar o Service Worker └── sw.js

É importante comentar que o Service Worker só irá funcionar dentro do caminho
que ele foi registrado. No exemplo acima o Service Worker vai funcionar somente
para o caminho https:/meudominio.com/blog/ em diante. O caminho
https:/meudominio.com/ não estará sob o controle do Service Worker. Caso
você precise aplicar o Service Worker em todo o seu domínio você precisa
registra-lo na raiz, em https:/meudominio.com/sw.js

Exemplo:

Service Worker:
https://meudominio.com/blog/sw.js
Página inicial: https://meudominio.com/ ←Service
Worker não consegue atuar neste endereço Página do blog:
https://meudominio.com/blog/outra-pagina
← Service Workers tem acesso e controla essa página

Certificado SSL (HTTPS)

Um Service Worker precisa obrigatoriamente está rodando em um domínio seguro,
com suporte a HTTPS. A única exceção neste caso é para localhost durante o
desenvolvimento.

Cross-Domain

Muitas das aplicações front-end tem seus arquivos assets servidos de CDN, o
problema aqui é quando esses arquivos são servidos para outro domínio.

Site: https://meudominio.com Arquivo Javascript:
https://minha-cdn.com/blog/main.js
Service Worker:
https://minha-cdn.com/blog/sw.js

Essa configuração acima, não vai funcionar, mesmo se se você configurar para
aceitar Cross-Domain o browser vai bloquear.

Solução:

Site: https://meudominio.com Arquivo
Javascript
:
https://meudominio.com/blog/main.js
Service Worker:
https://meudominio.com/blog/sw.js

Diversas aplicações front-end implementam um modelo de assinatura nos arquivos
para controlar o cache, e cada alteração no arquivo essa assinatura muda.

Exemplos de assinatura:

  • sw-d58e3582afa99040e27b92b13c8f2280.js
  • sw.js?_gc=20180101

Se você pretende trabalhar com Service Worker, você deve garantir que esse
comportamento não aconteça, caso contrário cada vez que uma alteração é feita no
arquivo, uma nova instalação será feita, sem remover a anterior. Basicamente
esse comportamento fará com que você tenha diversas versões instaladas ao mesmo
tempo e rodando juntas. Isso pode trazer diversos comportamentos inesperado na
sua aplicação.

Isso acontece por que o browser considera o caminho do arquivo como nome do
Service Worker.

Exemplo:

  • sw.js?_gc=123
  • sw.js?_gc=321

No exemplo acima, teríamos 2 Service Workers iguais instalados.

Se eu não posso controlar o cache com assinatura no arquivo, então como eu
controlo o cache do Service Worker?

Basicamente a resposta é, você não controla nenhum cache!

O ideal para esses arquivos de Service Worker é enviar no header parâmetros
informando o browser para não fazer nenhum tipo de cache:

// response header
Cache-Control: no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0

Por que? Basicamente o Browser faz download do arquivo e faz comparações
byte-to-byte para identificar que precisa instalar uma nova versão do
Service Worker.

Acesso ao DOM

Service Worker não é uma página web, logo você não tem acesso ao DOM, a maioria
dos recursos disponíveis no browser não vão funcionar. Se você precisar alterar
algo no DOM da página com base em algum evento no Service Worker, você vai
precisar enviar um evento com postMessage para página ativa. Na sua página
você terá que ter um addEventListener escutando e executando a ação que você
precisa. Vou falar mais sobre isso em outro post.

// in sw.js
this.clients.matchAll().then(clients => {
  clients.forEach(client => 
( { property, ...} ));
});

// in page.html
navigator.serviceWorker.addEventListener(
, event => { console.log(event.data) }, false);

LocalStorage

LocalStorage ou SessionStorage disponível no browser para armazenar pequenas
quantidades de dados não vão funcionar dentro de um Service Worker. Somente
IndexedDB está disponível até o momento.

Quem já mexeu com IndexedDB conhece dor de cabeça que é gerenciar ele. Para não
ter que passar esse trabalho todo, recomendo utilizar esse projeto que
implementa um interface similar ao LocalStorage para armazenar dados no
IndexedDB.

https://github.com/localForage/localForage

Librarys JavaScript

Algumas libs JS não foram pensadas para funcionar em um Service Worker, muitas
estão usando recursos que não são suportadas. Muitas tem referencia a variáveis
globais como window ou document que não existem dentro de uma instância
de Service Worker. Se está pensando em usar algo, procure por libs que ofereça
uma versão exclusiva para Service Workers.


Esses foram alguns pontos que gostaria de citar ao se trabalhar com Service
Workers. Apesar dos pontos acima, Service Worker é relativamente simples de
usar. Quase nunca consideramos usar recursos do browser similar a este por
acreditar que são avançados ou complexos de mais para nossa aplicação.

Um último ponto!

Nos exemplos que você verá pela WEB, quase todos são relacionados a PWA,
principalmente para trabalhar com dados off-line. Mas, Service Worker é muito
mais que somente disponibilizar dados off-line, você pode aproveita-lo para
resolver outros problemas, basta ter criatividade.

Você já fez algo com Service Workers? Deixe um comentário!

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *