Migra de Workbox v4 a v5

Esta guía se enfoca en los cambios rotundos que se presentan en Workbox v5, con ejemplos de los cambios que debes realizar al actualizar desde Workbox v4.

Cambios rotundos

Se cambió el nombre de las clases de complementos

Varios paquetes de Workbox v4 incluían clases llamadas Plugin. En la versión 5, se cambió el nombre de esas clases para que sigan el identificador de paquete de patrón + Plugin:

  • BackgroundSyncPlugin
  • BroadcastUpdatePlugin
  • CacheableResponsePlugin
  • ExpirationPlugin
  • RangeRequestsPlugin

Este cambio de nombre se aplica si usas las clases a través de importaciones de módulos o a través de los espacios de nombres de workbox.*.

Punto de reemplazo del manifiesto de almacenamiento previo en caché predeterminado

Anteriormente, cuando se usaba una de las herramientas de compilación en el modo "insertar manifiesto", se verificaba la presencia de precacheAndRoute([]) en el archivo de service worker de origen, con ese array vacío [] como marcador de posición para el punto en el que se insertaba el manifiesto de precaché.

En Workbox v5, cambió la lógica de reemplazo y ahora se usa self.__WB_MANIFEST de forma predeterminada como punto de inserción.

// v4:
precacheAndRoute([]);

// v5:
precacheAndRoute(self.__WB_MANIFEST);

Como se describe en este debate, creemos que este cambio proporciona una experiencia más simple y, al mismo tiempo, les da a los desarrolladores más control sobre la manera en que se usa el manifiesto insertado en el código de service worker personalizado. Si es necesario, puedes cambiar esta string de reemplazo mediante la opción de configuración injectionPoint.

Dos opciones que anteriormente eran compatibles con las rutas de navegación, blacklist y whitelist, cambiaron de nombre a denylist y allowlist.

Anteriormente, workbox-routing admitía un método, registerNavigationRoute(), que, de forma interna, hacía dos cosas:

  1. Se detectó si un evento fetch determinado tuvo o no un mode de 'navigate'.
  2. De ser así, se debe responder a esa solicitud con el contenido de una URL codificada y previamente almacenada en caché, independientemente de la URL a la que se navegue.

Este es un patrón común cuando se implementa la arquitectura de App Shell.

El segundo paso, que genera una respuesta mediante la lectura de la caché, se encuentra fuera de lo que vemos como las responsabilidades de workbox-routing. En cambio, la vemos como una funcionalidad que debería ser parte de workbox-precaching, a través de un nuevo método, createHandlerBoundToURL(). Este nuevo método puede funcionar de forma conjunta con la clase NavigationRoute existente en workbox-routing para lograr la misma lógica.

Si usas la opción navigateFallback en uno de los modos "generar SW" de la herramienta de compilación, el cambio se realizará automáticamente. Si ya configuraste las opciones navigateFallbackBlacklist o navigateFallbackWhitelist, cámbialas a navigateFallbackDenylist o navigateFallbackAllowlist, respectivamente.

Si estás usando el modo "inyectar manifiesto" o solo escribes el service worker por tu cuenta, y tu service worker de Workbox v4 llama directamente a registerNavigationRoute(), deberás realizar un cambio en el código para obtener el comportamiento equivalente.

// v4:
import {getCacheKeyForURL} from 'workbox-precaching';
import {registerNavigationRoute} from 'workbox-routing';

const appShellCacheKey = getCacheKeyForURL('/app-shell.html');
registerNavigationRoute(appShellCacheKey, {
  whitelist: [...],
  blacklist: [...],
});

// v5:
import {createHandlerBoundToURL} from 'workbox-precaching';
import {NavigationRoute, registerRoute} from 'workbox-routing';

const handler = createHandlerBoundToURL('/app-shell.html');
const navigationRoute = new NavigationRoute(handler, {
  allowlist: [...],
  denylist: [...],
});
registerRoute(navigationRoute);

Ya no necesitas llamar a getCacheKeyForURL(), ya que createHandlerBoundToURL() se encargará de eso por ti.

Eliminación de makeRequest() de las estrategias de Workbox.

Llamar a makeRequest() equivale principalmente a llamar a handle() en una de las clases workbox-strategy. Las diferencias entre los dos métodos eran tan leves que no tenía sentido mantener ambos métodos. Los desarrolladores que llamaron a makeRequest() deberían poder usar handle() sin realizar más cambios:

// v4:
const strategy = new StaleWhileRevalidate({...});
const response = await strategy.makeRequest({event, request});

// v5:
const strategy = new StaleWhileRevalidate({...});
const response = await strategy.handle({event, request});

En la versión 5, handle() trata a request como un parámetro obligatorio y no recurrirá a event.request. Asegúrate de pasar una solicitud válida cuando llames a handle().

workbox-broadcast-update siempre usa postMessage()

En la versión 4, la biblioteca workbox-broadcast-update usaba, de forma predeterminada, la API de Broadcast Channel para enviar mensajes cuando era compatible y recurría a postMessage() solo cuando Broadcast Channel no era compatible.

Nos dimos cuenta de que tener que escuchar dos posibles fuentes de mensajes entrantes dificultaba demasiado la escritura del código del cliente. Además, en algunos navegadores, las llamadas de postMessage() del service worker enviadas a páginas cliente se almacenan en búfer automáticamente hasta que se configura un objeto de escucha de eventos message. No hay almacenamiento en búfer con la API de Broadcast Channel y los mensajes transmitidos se descartan si se envían antes de que la página del cliente esté lista para recibirlos.

Por ese motivo, cambiamos workbox-broadcast-update para que siempre use postMessage() en la versión 5. Los mensajes se envían uno por uno a todas las páginas de cliente dentro del alcance del service worker actual.

Para adaptar este nuevo comportamiento, puedes quitar cualquier código que tengas en las páginas cliente que crearon instancias de BroadcastChannel y, en su lugar, configurar un objeto de escucha de eventos message en navigator.serviceWorker:

// v4:
const updatesChannel = new BroadcastChannel('api-updates');
updatesChannel.addEventListener('message', event => {
  const {cacheName, updatedUrl} = event.data.payload;
  // ... your code here ...
});

// v5:
// This listener should be added as early as possible in your page's lifespan
// to ensure that messages are properly buffered.
navigator.serviceWorker.addEventListener('message', event => {
  // Optional: ensure the message came from workbox-broadcast-update
  if (event.meta === 'workbox-broadcast-update') {
    const {cacheName, updatedUrl} = event.data.payload;
    // ... your code here ...
  }
});

Los usuarios de workbox-window no deberían necesitar hacer ningún cambio, ya que su lógica interna se actualizó para escuchar las llamadas de postMessage().

Las herramientas de compilación requieren Node.js v8 o versiones posteriores

Las versiones de Node.js anteriores a la v8 ya no son compatibles con workbox-webpack-plugin, workbox-build ni workbox-cli. Si ejecutas una versión de Node.js anterior a la 8, actualiza el entorno de ejecución a una versión compatible.

workbox-webpack-plugin Se requiere webpack v4 o superior

Si usas workbox-webpack-plugin, actualiza la configuración de webpack para usar, al menos, Webpack v4.

Reacondicionamiento de opciones de herramienta de compilación

Ya no se admiten varios parámetros de configuración workbox-build, workbox-cli y workbox-webpack-plugin. Por ejemplo, generateSW siempre creará un paquete de entorno de ejecución de Workbox local para ti, por lo que la opción importWorkboxFrom ya no tiene sentido.

Consulta la documentación de la herramienta relevante para conocer las listas de opciones admitidas.

Eliminación de generateSWString de workbox-build

Se quitó el modo generateSWString de workbox-build. Esperamos que el impacto de esta función sea mínimo, ya que workbox-webpack-plugin lo utilizó principalmente de forma interna.

Cambios opcionales

Cómo usar importaciones de módulos

Si bien este cambio es a) opcional y b) técnicamente era posible cuando se usaba Workbox v4, el mayor cambio que anticipamos al pasar a v5 es un modelo en el que puedes crear tu propio service worker agrupado importando los módulos de Workbox. Este enfoque es una alternativa a llamar a importScripts('/path/to/workbox-sw.js') en la parte superior de tu service worker y usar Workbox a través del espacio de nombres workbox.*.

Si estás usando una de las herramientas de compilación (workbox-webpack-plugin, workbox-build, workbox-cli) en el modo "generar SW", este cambio se producirá automáticamente. Todas esas herramientas generarán un paquete personalizado local del entorno de ejecución de Workbox junto con el código real necesario para implementar la lógica del service worker. En este caso, ya no hay dependencia de workbox-sw ni de la copia de la CDN de Workbox. Según el valor de tu configuración de inlineWorkboxRuntime, el entorno de ejecución de Workbox se dividirá en un archivo separado que se debe implementar junto con el service worker (cuando se establece en false, que es el valor predeterminado) o se incluirá intercalado junto con la lógica del service worker (cuando se establece en true).

Si usas las herramientas de compilación en el modo "inyectar manifiesto", o si no usas las herramientas de compilación de Workbox, puedes obtener más información para crear tu propio paquete de entorno de ejecución de Workbox en la guía existente Cómo usar Bundlers (webpack/Rollup) con Workbox.

La documentación y los ejemplos de la v5 se escriben suponiendo que el módulo importa la sintaxis, aunque el espacio de nombres workbox.* seguirá siendo compatible con Workbox v5.

Lee respuestas almacenadas en caché previamente

Algunos desarrolladores deben leer las respuestas almacenadas previamente en caché directamente desde la caché, en lugar de usarlas de forma implícita a través del método precacheAndRoute(). Un patrón común en la versión 4 sería, primero, obtener la clave de caché específica de la versión actual de un recurso almacenado en caché previamente y, luego, pasar esa clave junto con el nombre de caché del almacenamiento previo a caches.match() para obtener el Response.

Para simplificar este proceso, workbox-precaching en la v5 admite un nuevo método equivalente, matchPrecache():

// v4:
import {cacheNames} from 'workbox-core';
import {getCacheKeyForURL} from 'workbox-precaching';

const cachedResponse = await caches.match(
  getCacheKeyForURL(`/somethingPrecached`),
  {
    cacheName: cacheNames.precache,
  }
);

// v5:
import {matchPrecache} from 'workbox-precaching';

const cachedResponse = await matchPrecache(`/somethingPrecached`);

Adopción de TypeScript

En la versión 5, las bibliotecas del entorno de ejecución de Workbox se escriben en TypeScript. Si bien seguiremos publicando módulos y paquetes transpilados de JavaScript para adaptarnos a los desarrolladores que no hayan adoptado TypeScript, si usas TypeScript, deberías aprovechar la información de tipo precisa y siempre actualizada directamente desde el proyecto Workbox.

Migración de ejemplo

Esta confirmación ilustra una migración bastante compleja, con comentarios intercalados. Usa Rollup para incluir un entorno de ejecución personalizado de Workbox en el service worker final, en lugar de cargarlo desde la CDN.

Si bien no se abarcan todos los cambios rotundos, a continuación se incluyen el antes y el después de actualizar un archivo de service worker de la versión 4 a la 5, incluido el cambio a TypeScript.

Cómo obtener ayuda

Prevemos que la mayoría de las migraciones serán sencillas. Si tienes problemas que no se tratan en esta guía, abre un problema en GitHub para informarnos al respecto.