Transmite actualizaciones a las páginas con service workers

Andrew Guan
Andrew Guan
Demián Renzulli
Demián Renzulli

En algunas situaciones, es posible que el service worker deba comunicarse proactivamente con cualquiera de los pestañas que controla para informar sobre un evento determinado. Los siguientes son algunos ejemplos:

  • Informar a la página cuándo se ha instalado una nueva versión del service worker para que la página Puede mostrar el botón "Actualizar para actualizar" al usuario para acceder a la nueva funcionalidad. de inmediato.
  • Informa al usuario sobre un cambio en los datos almacenados en caché que ocurrió en el service worker, mostrar una indicación, como "La app está lista para trabajar sin conexión" o "Nueva versión de la “Contenido disponible”.
Diagrama que muestra un service worker que se comunica con la página para enviar una actualización.

Llamaremos a estos tipos de casos de uso en los que el service worker no necesita recibir un mensaje desde la página para iniciar una comunicación "de transmitir actualizaciones". En esta guía, revisaremos diferentes maneras de implementar este tipo de comunicación entre las páginas y los service workers las APIs del navegador y la biblioteca de Workbox.

Casos de producción

Tinder

La AWP de Tinder usa workbox-window para escuchar momentos importantes del ciclo de vida del service worker desde la página ("instalado", "controlado" y "activado"). De esa manera, cuando entra en juego un nuevo service worker, muestra una "Actualización disponible". para que puedan actualizar la AWP y acceder a las funciones más recientes:

Captura de pantalla de la aplicación web de Tinder "Actualización disponible" funcionalidad.
En la AWP de Tinder, el service worker le indica a la página que hay una nueva versión lista y, en la página, se muestra a los usuarios una "Actualización disponible" .

Squoosh

En la AWP de Squoosh, cuando el service worker ha almacenado en caché todos los para que funcione sin conexión, se envía un mensaje a la página con el mensaje "Listo para trabajar sin conexión" un aviso para informar al usuario sobre la función:

Una captura de pantalla de la aplicación web de Squoosh con el mensaje "Ready to work offline" funcionalidad.
En la AWP de Squoosh, el service worker transmite una actualización a la página cuando la caché está lista, y la página muestra el mensaje "Ready to work offline" tostada.

Uso de Workbox

Cómo detectar eventos de ciclo de vida de service worker

workbox-window proporciona una interfaz directa para escuchar importantes ciclo de vida de service worker eventos. De forma interna, la biblioteca usa APIs del cliente, como updatefound y statechange y proporciona objetos de escucha de eventos de nivel superior en el objeto workbox-window, lo que facilita que los usuarios consuman estos eventos.

El siguiente código de página te permite detectar cada vez que se instala una nueva versión del service worker. para que puedas comunicárselo al usuario:

const wb = new Workbox('/sw.js');

wb.addEventListener('installed', (event) => {
  if (event.isUpdate) {
    // Show "Update App" banner
  }
});

wb.register();

Cómo informar a la página sobre los cambios en los datos almacenados en caché

El paquete Workbox workbox-broadcast-update proporciona una forma estándar de notificar a los clientes de ventana que se actualizó una respuesta almacenada en caché. Este es más comúnmente utilizado junto con el método StalewhileRevalidate estrategia.

Para transmitir actualizaciones, agrega un broadcastUpdate.BroadcastUpdatePlugin a tus opciones de estrategia en la del service worker:

import {registerRoute} from 'workbox-routing';
import {StaleWhileRevalidate} from 'workbox-strategies';
import {BroadcastUpdatePlugin} from 'workbox-broadcast-update';

registerRoute(
  ({url}) => url.pathname.startsWith('/api/'),
  new StaleWhileRevalidate({
    plugins: [
      new BroadcastUpdatePlugin(),
    ],
  })
);

En tu app web, puedes escuchar estos eventos, como los siguientes:

navigator.serviceWorker.addEventListener('message', async (event) => {
  // Optional: ensure the message came from workbox-broadcast-update
  if (event.data.meta === 'workbox-broadcast-update') {
    const {cacheName, updatedUrl} = event.data.payload;

    // Do something with cacheName and updatedUrl.
    // For example, get the cached content and update
    // the content on the page.
    const cache = await caches.open(cacheName);
    const updatedResponse = await cache.match(updatedUrl);
    const updatedText = await updatedResponse.text();
  }
});

Uso de las APIs del navegador

Si la funcionalidad que proporciona Workbox no es suficiente para tus necesidades, usa el siguiente navegador APIs para implementar "actualizaciones de transmisión":

API de Broadcast Channel

El service worker crea un BroadcastChannel objeto y comienza a enviar mensajes nuevos a él. Cualquier contexto (p.ej., una página) en el que se desee recibir estos mensajes puede crear una instancia de una BroadcastChannel y, luego, implementa un controlador de mensajes para recibirlos.

Para informar a la página cuando se instala un nuevo service worker, usa el siguiente código:

// Create Broadcast Channel to send messages to the page
const broadcast = new BroadcastChannel('sw-update-channel');

self.addEventListener('install', function (event) {
  // Inform the page every time a new service worker is installed
  broadcast.postMessage({type: 'CRITICAL_SW_UPDATE'});
});

La página se suscribe a sw-update-channel para escuchar estos eventos:

// Create Broadcast Channel and listen to messages sent to it
const broadcast = new BroadcastChannel('sw-update-channel');

broadcast.onmessage = (event) => {
  if (event.data && event.data.type === 'CRITICAL_SW_UPDATE') {
    // Show "update to refresh" banner to the user.
  }
};

Esta es una técnica simple, pero su limitación es la compatibilidad con el navegador: al momento de esta redacción, Safari no admite esta API.

API del cliente

La API del cliente proporciona una forma directa manera de comunicarse con varios clientes desde el service worker iterando sobre un array de Objetos Client.

Usa el siguiente código del service worker para enviar un mensaje a la última pestaña enfocada:

// Obtain an array of Window client objects
self.clients.matchAll(options).then(function (clients) {
  if (clients && clients.length) {
    // Respond to last focused tab
    clients[0].postMessage({type: 'MSG_ID'});
  }
});

La página implementa un controlador de mensajes para interceptar estos mensajes:

// Listen to messages
navigator.serviceWorker.onmessage = (event) => {
     if (event.data && event.data.type === 'MSG_ID') {
         // Process response
   }
};

La API de cliente es una excelente opción para casos como la transmisión de información a varias pestañas activas. El La API es compatible con todos los navegadores principales, pero no todos sus métodos lo son. Verifica la compatibilidad del navegador antes y la usan.

Canal de mensajes

Message Channel requiere un paso de configuración inicial, pasando un puerto de la página al service worker, para establecer una canal de comunicación entre ellas. La página crea una instancia de un objeto MessageChannel y pasa un al service worker mediante la interfaz postMessage():

const messageChannel = new MessageChannel();

// Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
  messageChannel.port2,
]);

La página escucha mensajes implementando un mensaje "onmessage" en ese puerto:

// Listen to messages
messageChannel.port1.onmessage = (event) => {
  // Process message
};

El service worker recibe el puerto y guarda una referencia a él:

// Initialize
let communicationPort;

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'PORT_INITIALIZATION') {
    communicationPort = event.ports[0];
  }
});

Desde ese punto, puede enviar mensajes a la página llamando a postMessage() en la referencia al puerto:

// Communicate
communicationPort.postMessage({type: 'MSG_ID' });

MessageChannel puede ser más complejo de implementar debido a la necesidad de inicializar puertos, pero es son compatibles con todos los navegadores principales.

Próximos pasos

En esta guía, exploramos un caso particular de comunicación de ventana a service worker: "actualizaciones de transmisiones". Los ejemplos explorados incluyen escuchar a los service workers importantes de ciclo de vida y comunicarse con la página sobre los cambios en el contenido o los datos almacenados en caché. Puedes pensar de casos de uso más interesantes en los que el service worker se comunica proactivamente con la página sin haber recibido ningún mensaje antes.

Para obtener más patrones de comunicación de Window y service worker, consulta lo siguiente:

Recursos adicionales