Usar WebSockets em service workers

Este tutorial demonstra como se conectar a um WebSocket no service worker da extensão do Chrome. Veja um exemplo em funcionamento no GitHub (em inglês).

Contexto

A partir do Chrome 116, os service workers de extensão terão suporte aprimorado para WebSockets. Antes, um service worker poderia ficar inativo apesar de uma conexão WebSocket estar 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 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 dentro da janela de atividade do service worker de 30 segundos. Eles podem ser iniciados pelo servidor ou pela extensão. No exemplo a seguir, enviaremos uma mensagem normal da extensão do Chrome para o servidor para garantir que o service worker permaneça ativo.

Exemplo: sinal de atividade do WebSocket

Primeiro, precisamos garantir que nossa extensão só seja executada em versões do Chrome compatíveis com WebSockets em service workers definindo 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 de sinal de atividade a cada 20 segundos. O sinal de atividade é 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 (link em inglês)

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 regularmente um ping para o 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 
  );
}