Usar WebSockets em service workers

Este tutorial demonstra como se conectar a um WebSocket na extensão do Chrome. Você pode encontrar um exemplo funcional no GitHub (link em inglês).

Contexto

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

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

Exemplo: sinal de atividade WebSocket

Primeiro, precisamos garantir que nossa extensão seja executada apenas em versões do Chrome compatíveis com 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 worker de serviço ativo enviando uma mensagem de manutenção 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();
}

No keepAlive(), usamos setInterval(...) para enviar regularmente um ping ao servidor enquanto há 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 
  );
}