El paquete workbox-window
es un conjunto de módulos diseñados para ejecutarse en el
contexto window
, que
es decir, dentro de tus páginas web. Son un complemento del otro cuadro de trabajo
paquetes que se ejecutan en el service worker.
Las funciones y los objetivos clave de workbox-window
son los siguientes:
- Para simplificar el proceso de registro y actualización del service worker, desarrolladores a identificar los momentos más críticos del ciclo de vida del service worker, para responder a esos momentos.
- Para evitar que los desarrolladores cometan los errores más comunes,
- Permitir una comunicación más sencilla entre el código que se ejecuta en el service worker y el código que se ejecuta en la ventana.
Importa y usa la ventana de caja de trabajo
El punto de entrada principal para el paquete workbox-window
es la clase Workbox
.
puedes importarla en el código, ya sea desde nuestra CDN o mediante
Herramientas de paquetes de JavaScript.
Cómo usar nuestra CDN
La forma más fácil de importar la clase Workbox
en tu sitio es desde nuestra CDN:
<script type="module">
import {Workbox} from 'https://storage.googleapis.com/workbox-cdn/releases/6.4.1/workbox-window.prod.mjs';
if ('serviceWorker' in navigator) {
const wb = new Workbox('/sw.js');
wb.register();
}
</script>
Ten en cuenta que este ejemplo usa <script type="module">
y la sentencia import
para lo siguiente:
carga la clase Workbox
. Si bien podrías pensar que necesitas transpilar este
código para que funcione en navegadores más antiguos, en realidad, eso no es necesario.
Todos los principales navegadores que admiten service worker también admiten módulos de JavaScript nativos, por lo que bien publicar este código en cualquier navegador (los navegadores más antiguos simplemente lo ignoran).
Cómo cargar Workbox con agrupadores de JavaScript
Si bien no se requieren herramientas para usar workbox-window
, si tu
de desarrollo de software ya incluye un agrupador como
webpack o Rollup que funcione
con dependencias de npm, puedes usarlas para
cargar workbox-window
.
El primer paso
instalar
workbox-window
como una dependencia de tu aplicación:
npm install workbox-window
Luego, en uno de los archivos JavaScript de tu aplicación, el cuadro de trabajo import
y hace referencia al nombre del paquete workbox-window
:
import {Workbox} from 'workbox-window';
if ('serviceWorker' in navigator) {
const wb = new Workbox('/sw.js');
wb.register();
}
Si tu agrupador admite la división de código mediante sentencias de importación dinámicas,
También puedes cargar condicionalmente workbox-window
, lo que debería ayudar a reducir el
tamaño del paquete principal de tu página.
Aunque workbox-window
es bastante pequeño, no hay razón para que
debe cargarse con la lógica principal de la aplicación del sitio, como service workers,
por su propia naturaleza, son una mejora progresiva.
if ('serviceWorker' in navigator) {
const {Workbox} = await import('workbox-window');
const wb = new Workbox('/sw.js');
wb.register();
}
Conceptos avanzados de agrupación
A diferencia de los paquetes de Workbox que se ejecutan en el service worker, los archivos de compilación
a las que se hace referencia en workbox-window
main
y
Campos module
en
package.json
se transpilan a ES5. Esto los hace compatibles con los
herramientas de compilación, algunas de las cuales no permiten a los desarrolladores transpilar nada de
sus dependencias node_module
.
Si tu sistema de compilación sí te permite transpilar tus dependencias (o si necesitas transpilar nada de tu código), es mejor importar en su archivo fuente, en lugar del paquete en sí.
Estas son las distintas formas en que puedes importar Workbox
, junto con una explicación de
lo que mostrará cada uno:
// Imports a UMD version with ES5 syntax
// (pkg.main: "build/workbox-window.prod.umd.js")
const {Workbox} = require('workbox-window');
// Imports the module version with ES5 syntax
// (pkg.module: "build/workbox-window.prod.es5.mjs")
import {Workbox} from 'workbox-window';
// Imports the module source file with ES2015+ syntax
import {Workbox} from 'workbox-window/Workbox.mjs';
Ejemplos
Una vez que hayas importado la clase Workbox
, puedes usarla para registrar y
interactuar con tu service worker. Estos son algunos ejemplos de las formas en que
Workbox
en tu aplicación:
Registrar un service worker y notificar al usuario la primera vez que el service worker esté activo
Muchas aplicaciones web usan service workers para almacenar en caché previamente los recursos para que la app funcione. sin conexión en las cargas de página subsiguientes. En algunos casos, podría tener sentido informar le indica al usuario que la app está disponible sin conexión.
const wb = new Workbox('/sw.js');
wb.addEventListener('activated', event => {
// `event.isUpdate` will be true if another version of the service
// worker was controlling the page when this version was registered.
if (!event.isUpdate) {
console.log('Service worker activated for the first time!');
// If your service worker is configured to precache assets, those
// assets should all be available now.
}
});
// Register the service worker after event listeners have been added.
wb.register();
Notifica al usuario si se instaló un service worker, pero está atascado esperando para activarlo
Cuando una página controlada por un service worker existente registra un servicio nuevo de manera predeterminada, ese service worker no se activará hasta que todos los clientes controlados por el service worker inicial.
Esta es una fuente común de confusión para los desarrolladores, especialmente en los casos en que volver a cargar la página actual no provoca que se active el nuevo service worker.
Para ayudar a minimizar la confusión y aclarar cuándo ocurre esta situación,
La clase Workbox
proporciona un evento waiting
que puedes escuchar:
const wb = new Workbox('/sw.js');
wb.addEventListener('waiting', event => {
console.log(
`A new service worker has installed, but it can't activate` +
`until all tabs running the current version have fully unloaded.`
);
});
// Register the service worker after event listeners have been added.
wb.register();
Notificar al usuario sobre las actualizaciones de caché del paquete workbox-broadcast-update
El paquete workbox-broadcast-update
es una excelente forma de entregar contenido desde la caché (para una entrega rápida) y, al mismo tiempo,
ser capaz de informar al usuario sobre las actualizaciones de ese contenido (a través del
la estrategia de inactividad durante la revalidación).
Para recibir esas actualizaciones desde la ventana, puedes escuchar los eventos message
de
tipo CACHE_UPDATED
:
const wb = new Workbox('/sw.js');
wb.addEventListener('message', event => {
if (event.data.type === 'CACHE_UPDATED') {
const {updatedURL} = event.data.payload;
console.log(`A newer version of ${updatedURL} is available!`);
}
});
// Register the service worker after event listeners have been added.
wb.register();
Cómo enviar al service worker una lista de URL a la caché
Para algunas aplicaciones, es posible conocer todos los recursos que se deben se almacenan en caché por adelantado al momento de la compilación, pero algunas aplicaciones entregan páginas completamente diferentes. según la URL a la que llega primero el usuario.
En el caso de las aplicaciones de esta última categoría, tendría sentido almacenar solo los recursos en caché.
que el usuario necesitaba para la página particular que visitó. Cuando uses
workbox-routing
, puedes
enviará al router una lista de las URLs a la caché, y almacenará en caché esas URLs según
a las reglas definidas en el propio router.
Este ejemplo envía una lista de las URLs cargadas por la página al router cada vez que un se active un nuevo service worker. Ten en cuenta que es correcto enviar todas las URLs porque solo se almacenarán en caché las URLs que coincidan con una ruta definida en el service worker:
const wb = new Workbox('/sw.js');
wb.addEventListener('activated', event => {
// Get the current page URL + all resources the page loaded.
const urlsToCache = [
location.href,
...performance.getEntriesByType('resource').map(r => r.name),
];
// Send that list of URLs to your router in the service worker.
wb.messageSW({
type: 'CACHE_URLS',
payload: {urlsToCache},
});
});
// Register the service worker after event listeners have been added.
wb.register();
Momentos importantes del ciclo de vida de los service workers
El ciclo de vida de un service worker y comprenderlos por completo puede ser un desafío. En parte, es Es tan complejo que debe manejar todas las situaciones limítrofes para todos los usos posibles service worker (por ejemplo, registrar más de un service worker, registrar diferentes service workers en diferentes tramas, registrando nombres diferentes, etc.).
Pero la mayoría de los desarrolladores que implementan service workers no deberían preocuparse en todos estos casos límite porque su uso es bastante simple. La mayoría de los desarrolladores registran solo un service worker por carga de página y no cambian su nombre el archivo que implementan en el servidor.
La clase Workbox
adopta esta vista más simple para el ciclo de vida del service worker
mediante la división de todos los registros de service worker en dos categorías: la instancia
service worker registrado, propio y un service worker externo:
- Service worker registrado: Es un service worker que comenzó a instalarse como un
resultado de la instancia de
Workbox
que llama aregister()
o el resultado Service worker si llamar aregister()
no activó un eventoupdatefound
en el registro. - Service worker externo: Un service worker que empezó a instalarse.
independientemente de la instancia de
Workbox
que llama aregister()
. Normalmente, ocurre cuando un usuario tiene una versión nueva de tu sitio abierta en otra pestaña. Cuando un el evento se origina en un service worker externo, elisExternal
del evento se configurará comotrue
.
Con estos dos tipos de service workers en mente, aquí hay un desglose de momentos importantes del ciclo de vida del service worker, junto con recomendaciones para desarrolladores sobre cómo manejarlos:
La primera vez que se instala un service worker
Tal vez quieras tratar la primera vez que un service worker instala de manera diferente a cómo tratas todas las actualizaciones futuras.
En workbox-window
, puedes diferenciar entre la primera versión
la instalación y las actualizaciones futuras consultando la propiedad isUpdate
en cualquiera de
los siguientes eventos. Durante la primera instalación, isUpdate
será
false
const wb = new Workbox('/sw.js');
wb.addEventListener('installed', event => {
if (!event.isUpdate) {
// First-installed code goes here...
}
});
wb.register();
Cuando se encuentra una versión actualizada del service worker
Cuando un nuevo service worker comienza a instalarse, pero actualmente hay una versión existente
controlando la página, la propiedad isUpdate
de todos los siguientes eventos se
ser true
.
Cómo reaccionas en esta situación suele ser diferente de la primera para la instalación, ya que debes administrar cuándo y cómo recibirá la actualización el usuario.
Cuando se encuentra una versión inesperada del service worker
A veces, los usuarios mantienen tu sitio abierto en una pestaña en segundo plano durante mucho tiempo tiempo. Incluso pueden abrir una nueva pestaña y navegar hasta tu sitio sin darse cuenta ya tienen tu sitio abierto en una pestaña en segundo plano. En esos casos, es es posible tener dos versiones de tu sitio ejecutándose al mismo tiempo y que puede presentarte algunos problemas interesantes para ti como desarrollador.
Supongamos que tienes la pestaña A en ejecución v1 de tu sitio y la pestaña B con la versión 2. Cuando se cargue la pestaña B, la controlará la versión de tu servicio que se envió con la v1, pero la página que mostró el servidor (si se usa un estrategia de almacenamiento en caché centrada en la red para tus solicitudes de navegación) contendrá todos tus recursos de la v2.
Sin embargo, esto generalmente no es un problema para la pestaña B, ya que cuando escribiste tu v2 de la versión 1. Sin embargo, podría ser para la pestaña A,ya que el código de la v1 no podría haber predicho cambios que podría introducir tu código de la v2.
Para ayudar a controlar estas situaciones, workbox-window
también despacha el ciclo de vida
eventos cuando detecta una actualización de un servidor "externo" service worker, en el que
"externo" significa que cualquier versión que no sea la actual Workbox
instancia registrada.
A partir de Workbox v6 y versiones posteriores, estos eventos son equivalentes a los eventos documentados
arriba, con la adición de una propiedad isExternal: true
configurada en cada evento
. Si tu aplicación web necesita implementar una lógica específica para controlar un
“externo” puedes buscar esa propiedad en tus controladores de eventos.
Cómo evitar errores comunes
Una de las funciones más útiles que proporciona Workbox es el registro del desarrollador. Y
esto es especialmente cierto para workbox-window
.
Sabemos que desarrollar con service workers a menudo puede ser confuso suceden al contrario de lo que esperas, puede ser difícil saber por qué.
Por ejemplo, cuando realizas un cambio en tu service worker y vuelves a cargar la página, es posible que no veas ese cambio en tu navegador. El motivo más probable de esto, significa que tu service worker aún está esperando para activarse.
Sin embargo, cuando registres un service worker con la clase Workbox
, verás lo siguiente:
de todos los cambios de estado del ciclo de vida en la consola para desarrolladores, que debería
ayuda a depurar el motivo por el cual las cosas no son como esperabas.
Además, un error común que cometen los desarrolladores al usar un service worker por primera vez es para registrar un service worker en la alcance incorrecto.
Para evitar que esto suceda, la clase Workbox
te advertirá si la
que registra el service worker no está dentro del alcance de ese service worker. Lo
También te advierte cuando tu service worker está activo, pero aún no
controlar la página:
Comunicación de la ventana al service worker
El uso más avanzado de service worker implica muchos mensajes entre el
service worker y la ventana. La clase Workbox
también ayuda con esto, ya que
a la hora de proporcionar un método messageSW()
, que postMessage()
service worker registrado y esperar una respuesta.
Si bien puedes enviar datos al service worker en cualquier formato, el formato que se comparte por todos los paquetes de Workbox es un objeto con tres propiedades (las dos últimas son opcional):
Los mensajes enviados con el método messageSW()
usan MessageChannel
para que el receptor
para responder a ellas. Para responder un mensaje, puedes llamar
event.ports[0].postMessage(response)
en tu objeto de escucha de eventos de mensajes. El
El método messageSW()
muestra una promesa que se resolverá a lo que sea response
.
con la que respondes.
Aquí hay un ejemplo de cómo enviar mensajes desde la ventana al service worker
obtener una respuesta. El primer bloque de código es el objeto de escucha de mensajes del
service worker, y el segundo bloque usa la clase Workbox
para enviar
y espera la respuesta:
Código en sw.js:
const SW_VERSION = '1.0.0';
addEventListener('message', event => {
if (event.data.type === 'GET_VERSION') {
event.ports[0].postMessage(SW_VERSION);
}
});
Código en main.js (que se ejecuta en la ventana):
const wb = new Workbox('/sw.js');
wb.register();
const swVersion = await wb.messageSW({type: 'GET_VERSION'});
console.log('Service Worker version:', swVersion);
Cómo administrar incompatibilidades de versiones
En el ejemplo anterior, se muestra cómo podrías implementar la verificación del service worker de la versión en la ventana. Este ejemplo se usa porque, cuando envías entre la ventana y el service worker, es fundamental es posible que tu service worker no esté ejecutando la misma versión de de que se ejecuta el código de tu página y la solución para este problema es diferente según si tus páginas se publican primero en la red o que prioriza la caché.
Primero la red
Cuando publiquen primero sus páginas en la red, sus usuarios siempre la versión más reciente del código HTML de tu servidor. Sin embargo, la primera vez que un usuario vuelve a visitar tu sitio (después de implementar una actualización), el HTML que obtendrá para obtener la última versión, pero el service worker que se ejecuta en su navegador una versión instalada previamente (posiblemente, muchas versiones antiguas).
Es importante comprender esta posibilidad, ya que si JavaScript carga la versión actual de tu página envía un mensaje a una versión anterior de tu service worker, tal vez esa versión no sepa cómo responder (o puede responder con un formato incompatible).
Por lo tanto, es buena idea crear siempre las versiones del service worker las versiones compatibles antes de realizar cualquier trabajo crítico.
Por ejemplo, en el código anterior, si la versión del service worker que muestra esa
La llamada messageSW()
es anterior a la versión esperada, por lo que recomendamos esperar
hasta que se encuentre una actualización (lo que debería ocurrir cuando llamas a register()
). En
en ese punto puedes notificar
al usuario o hacer una actualización, o puedes
omite la fase de espera
para activar de inmediato el nuevo service worker.
Primero en caché
A diferencia de cuando publica páginas
primero en la red, cuando publica sus páginas en caché
primero, sabrás que, al principio, tu página siempre será la misma versión que
tu service worker (porque eso es lo que lo entrega). Por eso, es seguro
usar messageSW()
de inmediato.
Sin embargo, si se encuentra una versión actualizada del service worker y se activa
Cuando tu página llame a register()
(es decir, omites la fase de espera intencionalmente)
es posible que ya no sea seguro enviarle mensajes.
Una estrategia para manejar esta posibilidad es usar un esquema de control de versiones que te permite diferenciar entre actualizaciones rotundas y no rotundas, y, en caso de una actualización rotunda, sabrías que no es seguro enviar un mensaje service worker. Debes advertirle al usuario que está ejecutando una aplicación de la página y sugerir que vuelvan a cargar para obtener la actualización.
Omitir asistente de espera
Una convención de uso común para la mensajería de ventana a service worker es enviar un
Mensaje {type: 'SKIP_WAITING'}
para indicar a un service worker que está instalado en
omitir la fase de espera
y activarlas.
A partir de Workbox v6, se puede usar el método messageSkipWaiting()
para enviar un
mensaje {type: 'SKIP_WAITING'}
al service worker en espera asociado
el registro actual del service worker. No hará nada en silencio si no hay
service worker de espera.
Tipos
Workbox
Es una clase que facilita el manejo del registro de service worker, las actualizaciones y a eventos de ciclo de vida de service worker.
Propiedades
-
constructor
void
Crea una instancia de Workbox nueva con una URL de secuencia de comandos y un service worker. opciones de estado. La URL y las opciones de la secuencia de comandos serán las mismas que se usan cuando Llamando a navigator.serviceWorker.register(scriptURL, options).
La función
constructor
se ve de la siguiente manera:(scriptURL: string | TrustedScriptURL, registerOptions?: object) => {...}
-
scriptURL
string | TrustedScriptURL
La secuencia de comandos del service worker asociada con esta instancia. Con un Se admite
TrustedScriptURL
. -
registerOptions
objeto opcional
-
muestra
-
-
activo
Promise<ServiceWorker>
-
controlando
Promise<ServiceWorker>
-
getSW
void
Se resuelve con una referencia a un service worker que coincida con la URL de la secuencia de comandos. de esta instancia en cuanto esté disponible.
Si, al momento del registro, ya hay un servicio activo o en espera trabajador con una URL de secuencia de comandos que coincida, se usará service worker que tenga prioridad sobre el service worker activo si ambos de respuesta, ya que el service worker en espera se habría registrado más recientemente). Si no hay un service worker activo o en espera que coincida en el registro tiempo, la promesa no se resolverá hasta que se encuentre una actualización y comience durante la instalación, momento en el que se usa el service worker de instalación.
La función
getSW
se ve de la siguiente manera:() => {...}
-
muestra
Promise<ServiceWorker>
-
-
messageSW
void
Envía el objeto de datos pasado al service worker que registró este (a través de
workbox-window.Workbox#getSW
) y resuelve con una respuesta (si la hubiera).Se puede configurar una respuesta en un controlador de mensajes en el service worker llamando a
event.ports[0].postMessage(...)
, lo que resolverá la promesa que devuelvemessageSW()
. Si no se establece una respuesta, la promesa nunca resolver.La función
messageSW
se ve de la siguiente manera:(data: object) => {...}
-
datos
objeto
Un objeto para enviar al service worker
-
muestra
Promesa<cualquiera>
-
-
messageSkipWaiting
void
Se envía un mensaje
{type: 'SKIP_WAITING'}
al service worker que actualmente se encuentra en el estadowaiting
asociado con el registro actual.Si no hay un registro actual o si no hay un service worker, es
waiting
, llamar a esto no tendrá ningún efecto.La función
messageSkipWaiting
se ve de la siguiente manera:() => {...}
-
regístrese
void
Registra un service worker para la URL y el servicio de esta secuencia de comandos de instancias opciones de trabajadores de primera línea. De forma predeterminada, este método retrasa el registro hasta después de se cargó la ventana.
La función
register
se ve de la siguiente manera:(options?: object) => {...}
-
opciones
objeto opcional
-
inmediato
booleano opcional
-
-
muestra
Promise<ServiceWorkerRegistration>
-
-
update
void
Busca actualizaciones del service worker registrado.
La función
update
se ve de la siguiente manera:() => {...}
-
muestra
Promesa<void>
-
WorkboxEventMap
Propiedades
-
Activado
-
activando
-
controlando
-
Instalada
-
instala
-
mensaje
-
redundante
-
esperando
WorkboxLifecycleEvent
Propiedades
-
isExternal
booleano opcional
-
isUpdate
booleano opcional
-
originalEvent
Evento opcional
-
sw
ServiceWorker opcional
-
objetivo
WorkboxEventTarget opcional
-
tipo
typeOperator
WorkboxLifecycleEventMap
Propiedades
-
Activado
-
activando
-
controlando
-
Instalada
-
instala
-
redundante
-
esperando
WorkboxLifecycleWaitingEvent
Propiedades
-
isExternal
booleano opcional
-
isUpdate
booleano opcional
-
originalEvent
Evento opcional
-
sw
ServiceWorker opcional
-
objetivo
WorkboxEventTarget opcional
-
tipo
typeOperator
-
wasWaitingBeforeRegister
booleano opcional
WorkboxMessageEvent
Propiedades
-
datos
cualquiera
-
isExternal
booleano opcional
-
originalEvent
Evento
-
ports
typeOperator
-
sw
ServiceWorker opcional
-
objetivo
WorkboxEventTarget opcional
-
tipo
"mensaje"
Métodos
messageSW()
workbox-window.messageSW(
sw: ServiceWorker,
data: object,
)
Envía un objeto de datos a un service worker a través de postMessage
y lo resuelve con
una respuesta (si la hubiera).
Se puede configurar una respuesta en un controlador de mensajes en el service worker
llamando a event.ports[0].postMessage(...)
, lo que resolverá la promesa
que devuelve messageSW()
. Si no se establece una respuesta, la promesa no
resolver.
Parámetros
-
sw
ServiceWorker
El service worker al que se envía el mensaje.
-
datos
objeto
Un objeto para enviar al service worker.
Muestra
-
Promesa<cualquiera>