Módulos de ES en service workers

Una alternativa moderna a importScripts().

Segundo plano

Módulos de ES hace tiempo que han sido uno de los favoritos de los desarrolladores. Además de un de otros beneficios, ofrecen la promesa de un formato universal de módulo en el que se puede compartir el código una vez y se ejecutan en navegadores y en entornos de ejecución alternativos, como Node.js. Mientras que todos los navegadores modernos ofrecen compatibilidad con módulos ES, no todos ofrecen asistencia en todas partes que de que se pueda ejecutar el código. En concreto, la compatibilidad con la importación de módulos de ES dentro de un del navegador service worker está empezando a estar disponible de forma más generalizada.

En este artículo, se detalla el estado actual de la compatibilidad con módulos de ES en los service workers en todos los navegadores comunes, junto con algunos problemas que se deben evitar y las prácticas recomendadas para enviar código de service worker retrocompatible.

Casos de uso

El caso de uso ideal para módulos ES dentro de service workers es cargar un una biblioteca moderna o un código de configuración que se comparte con otros entornos de ejecución los módulos de ES compatibles.

Intentar compartir código de esta forma antes de los módulos de ES implica usar modelos “universal” de módulos, como UMD, que incluyen código estándar innecesario y la escritura de código que realizó cambios en modelos expuestos de forma global variables.

Las secuencias de comandos importadas a través de módulos de ES pueden activar el service worker actualización de flujo si su contenido cambia, que coincide con el comportamiento de importScripts()

Limitaciones actuales

Solo importaciones estáticas

Los módulos de ES se pueden importar de dos maneras: de forma estática con la sintaxis import ... from '...' de forma dinámica con el método import(). En un service worker, solo la estática la sintaxis de gcloud.

Esta limitación es análoga a una restricción similar se realiza con el uso de importScripts(). Las llamadas dinámicas a importScripts() no suceden funciona dentro de un service worker, y todas las llamadas a importScripts(), que son intrínsecamente síncrono, debe completarse antes de que el service worker complete su Fase install: Esta restricción garantiza que el navegador conozca almacenar en caché implícitamente todo el código JavaScript necesario para la configuración para implementarlos durante la instalación.

Con el tiempo, esta restricción podría eliminarse, y ES importaciones de módulos es posible que estén permitidos. Por ahora, asegúrate de usar solo la sintaxis estática dentro de un service worker.

¿Qué ocurre con otros trabajadores?

Compatibilidad con Módulos de ES en "dedicated" trabajadores, es decir, aquellos construido con new Worker('...', {type: 'module'}), es más generalizada y es compatible con Chrome y Edge desde versión 80, así como versiones recientes de Safari. Las importaciones de módulos de ES estáticas y dinámicas se admiten en trabajadores dedicados.

Chrome y Edge admiten módulos ES compatibles en trabajadores compartidos desde la versión 83, pero no otro navegador ofrece asistencia en este momento.

No se admite la importación de mapas.

Importar mapas permitir entornos de ejecución para reescribir especificadores de módulos para, por ejemplo, anteponer al URL de una CDN preferida desde la que se pueden cargar los módulos de ES.

Mientras que Chrome y Edge versión 89 y posteriores admiten la importación de mapas, actualmente no se puede usar con el servicio trabajadores.

Navegadores compatibles

Los módulos de ES en los service workers son compatibles con Chrome y Edge a partir de versión 91.

Safari agregó compatibilidad Versión de la Versión preliminar de tecnología 122, y los desarrolladores deberían esperar que esta funcionalidad se lance en la versión de Safari en el futuro.

Ejemplo de código

Este es un ejemplo básico de cómo usar un módulo de ES compartido en el window de una app web. y registra un service worker que usa el mismo módulo ES:

// Inside config.js:
export const cacheName = 'my-cache';
// Inside your web app:
<script type="module">
  import {cacheName} from './config.js';
  // Do something with cacheName.

  await navigator.serviceWorker.register('es-module-sw.js', {
    type: 'module',
  });
</script>
// Inside es-module-sw.js:
import {cacheName} from './config.js';

self.addEventListener('install', (event) => {
  event.waitUntil((async () => {
    const cache = await caches.open(cacheName);
    // ...
  })());
});

Compatibilidad con versiones anteriores

El ejemplo anterior funcionaría bien si todos los navegadores fueran compatibles con los módulos ES en service workers, pero al momento de escribir este no es el caso.

Para adaptarse a los navegadores que no tienen compatibilidad integrada, puedes ejecutar tu de Terraform mediante un Agrupador compatible con módulos de ES para crear un que incluya todo el código del módulo intercalado, y funcionará navegadores anteriores. De manera alternativa, si los módulos que intentas importar son ya está disponible, incluida en IIFE o UMD, puedes importarlos usando importScripts()

Una vez que tengas disponibles dos versiones de tu service worker; una que use ES módulos y el otro que no, deberás detectar cuál es la configuración que el navegador admite y registra la secuencia de comandos del service worker correspondiente. Los mejores las prácticas para detectar la asistencia se encuentran en constante cambio, pero puede seguir debate en esta Problema de GitHub para recomendaciones.

_Foto de Vlado Paunovic en Unsplash_