ES-модули в сервис-воркерах

Современная альтернатива importScripts().

Фон

Модули ES уже давно стали фаворитом разработчиков. В дополнение к ряду других преимуществ , они обещают универсальный формат модуля, в котором общий код может быть выпущен один раз и запускаться в браузерах и в альтернативных средах выполнения, таких как Node.js. Хотя все современные браузеры предлагают некоторую поддержку модулей ES, не все они предлагают поддержку везде, где может быть запущен код. В частности, поддержка импорта ES-модулей внутри сервис-воркера браузера только начинает становиться более доступной.

В этой статье подробно описано текущее состояние поддержки модулей ES в сервис-воркерах в распространенных браузерах, а также некоторые ошибки, которых следует избегать, а также рекомендации по доставке обратно совместимого кода сервис-воркеров.

Варианты использования

Идеальный вариант использования модулей ES внутри сервисных работников — загрузка современной библиотеки или кода конфигурации, совместно используемого с другими средами выполнения, поддерживающими модули ES.

Попытка поделиться кодом таким образом до появления модулей ES повлекла за собой использование старых «универсальных» форматов модулей, таких как UMD , которые включали ненужный шаблон, и написание кода, который вносил изменения в глобально открытые переменные.

Скрипты, импортированные через модули ES, могут инициировать поток обновления Service Worker, если их содержимое изменится, что соответствует поведению importScripts() .

Текущие ограничения

Только статический импорт

Модули ES можно импортировать одним из двух способов: либо статически , используя синтаксис import ... from '...' , либо динамически , используя метод import() . Внутри сервис-воркера в настоящее время поддерживается только статический синтаксис.

Это ограничение аналогично аналогичному ограничению, налагаемому на использование importScripts() . Динамические вызовы importScripts() не работают внутри сервис-воркера, и все вызовы importScripts() , которые по своей сути являются синхронными, должны завершиться до того, как сервис-воркер завершит этап install . Это ограничение гарантирует, что браузер знает и может неявно кэшировать весь код JavaScript, необходимый для реализации сервис-воркера во время установки.

Со временем это ограничение может быть снято и будет разрешен динамический импорт модулей ES. На данный момент убедитесь, что вы используете статический синтаксис только внутри сервис-воркера.

А как насчет других работников?

Поддержка модулей ES в «выделенных» рабочих процессах — тех, которые созданы с помощью new Worker('...', {type: 'module'}) - более широко распространена и поддерживается в Chrome и Edge, начиная с версии 80 , а также последние версии Safari. В выделенных рабочих процессах поддерживается как статический, так и динамический импорт модулей ES.

Chrome и Edge поддерживают модули ES в общих рабочих процессах начиная с версии 83 , но на данный момент ни один другой браузер не поддерживает эту поддержку.

Нет поддержки импорта карт.

Карты импорта позволяют средам выполнения перезаписывать спецификаторы модулей, например, добавляя URL-адрес предпочтительного CDN, из которого можно загружать модули ES.

Хотя Chrome и Edge версии 89 и выше поддерживают карты импорта, в настоящее время их нельзя использовать с работниками службы.

Поддержка браузера

Модули ES в сервис-воркерах поддерживаются в Chrome и Edge, начиная с версии 91 .

Safari добавил поддержку в Technology Preview 122 Release , и разработчикам следует ожидать появления этой функции в стабильной версии Safari в будущем.

Пример кода

Это базовый пример использования общего модуля ES в контексте window веб-приложения с одновременной регистрацией сервисного работника, который использует тот же модуль 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);
    // ...
  })());
});

Обратная совместимость

Приведенный выше пример работал бы нормально, если бы все браузеры поддерживали ES-модули в сервис-воркерах, но на момент написания этой статьи это не так.

Чтобы обеспечить поддержку браузеров, не имеющих встроенной поддержки, вы можете запустить сценарий сервисного работника через пакетный модуль, совместимый с модулем ES, чтобы создать сервисный работник, который включает в себя весь встроенный код модуля и будет работать в старых браузерах. Альтернативно, если модули, которые вы пытаетесь импортировать, уже доступны в формате IIFE или UMD , вы можете импортировать их с помощью importScripts() .

Если у вас есть две доступные версии вашего сервис-воркера — одна использует модули ES, а другая — нет, вам нужно будет определить, что поддерживает текущий браузер, и зарегистрировать соответствующий сценарий сервис-воркера. Рекомендации по обнаружению поддержки в настоящее время постоянно меняются, но вы можете следить за обсуждением в этом выпуске GitHub, чтобы получить рекомендации.

_Фото Владо Пауновича на Unsplash _