Usar WebSockets em service workers

Este tutorial demonstra como se conectar a um WebSocket no service worker da extensão do Chrome. Confira um exemplo funcional no GitHub.

Contexto

A partir do Chrome 116, os service workers de extensão têm suporte aprimorado para WebSockets. Antes, um service worker podia ficar inativo, mesmo que uma conexão WebSocket estivesse ativa, se nenhum outro evento de extensão ocorresse por 30 segundos. Isso encerrava o service worker e fechava a conexão WebSocket. Para mais informações sobre o ciclo de vida do service worker de extensão, leia o guia do service worker de extensão.

A partir do Chrome 116, é possível manter um service worker com uma conexão WebSocket ativa trocando mensagens na janela de atividade do service worker de 30 segundos. Elas podem ser iniciadas no servidor ou na extensão. No exemplo a seguir, vamos enviar uma mensagem normal da extensão do Chrome para o servidor para garantir que o service worker permaneça ativo.

Exemplo: keepalive do WebSocket

Primeiro, precisamos garantir que nossa extensão seja executada apenas em versões do Chrome que ofereçam suporte a WebSockets em service workers. Para isso, defina a versão mínima do Chrome como 116 no manifesto:

manifest.json:

{
  ...
  "minimum_chrome_version": "116",
  ...
}

Em seguida, podemos manter o service worker ativo enviando uma mensagem keepalive a cada 20 segundos. O keepalive é iniciado quando o service worker se conecta ao WebSocket. O exemplo de cliente WebSocket a seguir registra mensagens e chama keepAlive() quando o evento onopen é acionado:

service-worker.js

let webSocket = null;

function connect() {
  webSocket = new WebSocket('wss://example.com/ws');

  webSocket.onopen = (event) => {
    console.log('websocket open');
    keepAlive();
  };

  webSocket.onmessage = (event) => {
    console.log(`websocket received message: ${event.data}`);
  };

  webSocket.onclose = (event) => {
    console.log('websocket connection closed');
    webSocket = null;
  };
}

function disconnect() {
  if (webSocket == null) {
    return;
  }
  webSocket.close();
}

Dentro de keepAlive(), usamos setInterval(...) para enviar um ping regularmente ao servidor enquanto houver uma conexão WebSocket ativa:

function keepAlive() {
  const keepAliveIntervalId = setInterval(
    () => {
      if (webSocket) {
        webSocket.send('keepalive');
      } else {
        clearInterval(keepAliveIntervalId);
      }
    },
    // Set the interval to 20 seconds to prevent the service worker from becoming inactive.
    20 * 1000 
  );
}