Moduły ES w skryptach service worker

Nowoczesna alternatywa dla funkcji importScripts().

Moduły ES już od jakiegoś czasu są ulubionymi deweloperami. Poza wieloma innymi korzyściami rozwiązania te zapewniają uniwersalny format modułów, w którym wspólny kod można udostępnić raz i uruchomić w przeglądarkach i w alternatywnych środowiskach wykonawczych, takich jak Node.js. Wszystkie nowoczesne przeglądarki obsługują niektóre moduły ES, ale nie wszystkie zapewniają pomoc wszędzie, w których można uruchomić kod. W szczególności obsługa importowania modułów ES w usługach workera przeglądarki dopiero zaczyna być bardziej dostępna.

W tym artykule znajdziesz informacje o obecnym stanie obsługi modułów ES w skryptach service worker w popularnych przeglądarkach, a także o kilku zagrożeniach, których należy unikać, oraz o sprawdzonych metodach przesyłania zgodnego wstecznie kodu mechanizmu Service Worker.

Przypadki użycia

Idealnym przypadkiem użycia modułów ES w ramach mechanizmów Service Worker jest ładowanie nowoczesnej biblioteki lub kodu konfiguracji, który jest współużytkowany przez inne środowiska wykonawcze obsługujące moduły ES.

Próba udostępnienia kodu w ten sposób przed wprowadzeniem modułów ES wymagała użycia starszych formatów „uniwersalnych” modułów, takich jak UMD, które zawierają niepotrzebne szablony, oraz napisania kodu, który wprowadzał zmiany w globalnie udostępnionych zmiennych.

Skrypty zaimportowane za pomocą modułów ES mogą aktywować proces aktualizacji skryptu service worker, jeśli ich zawartość ulegnie zmianie, zgodnie z zachowaniem importScripts().

Obecne ograniczenia

tylko import statyczny;

Moduły ES mogą być importowane na 2 sposoby: statycznie, za pomocą składni import ... from '...', lub dynamicznie, za pomocą metody import(). W skrypcie service worker obecnie obsługiwana jest tylko składnia statyczna.

To ograniczenie jest analogiczne do podobnego ograniczenia stosowanego w przypadku korzystania z importScripts(). Dynamiczne wywołania do importScripts() nie działają w ramach usługi wtyczki. Wszystkie wywołania importScripts(), które są z zasady synchroniczne, muszą zostać zakończone, zanim usługa wtyczki zakończy fazę install. To ograniczenie daje przeglądarce dostęp do informacji o całym kodzie JavaScript potrzebnym do zaimplementowania mechanizmu Service Worker w trakcie instalacji. Dzięki temu przeglądarka wie, że buforuje ją w pamięci podręcznej.

Ostatecznie to ograniczenie może zostać zniesione, a dynamiczne importowanie modułów ES może zostać dozwolone. Na razie używaj tylko składni statycznej w ramach usługi workera.

A co z innymi pracownikami?

Obsługa modułów ES w „wyznaczonych” workerach (zbudowanych za pomocą new Worker('...', {type: 'module'})) jest bardziej rozpowszechniona i jest obsługiwana w Chrome i Edge od wersji 80, a także w najnowszych wersjach przeglądarki Safari. W przypadku dedykowanych pracowników obsługiwane są zarówno importy statycznych, jak i dynamicznych modułów ES.

Chrome i Edge obsługują moduły ES w współdzielonych instancjach roboczych od wersji 83, ale obecnie żadna inna przeglądarka nie obsługuje takich modułów.

Brak obsługi map importowanych

Mapy importowania umożliwiają środowiskom uruchomieniowym przepisywanie specyfikatorów modułów, np. dołączanie na początku adresu URL preferowanej sieci CDN, z której można wczytywać moduły ES.

Chociaż przeglądarki Chrome i Edge w wersji 89 lub nowszej obsługują mapy importowania, obecnie nie można ich używać z mechanizmami Service Worker.

Obsługa przeglądarek

Moduły ES w usługach działających w tle są obsługiwane w Chrome i Edge od wersji 91.

Safari dodało obsługę w wersji 122 wersji Technology Preview, a deweloperzy powinni spodziewać się, że ta funkcja zostanie w przyszłości udostępniona w stabilnej wersji Safari.

Przykładowy kod

Oto podstawowy przykład użycia udostępnionego modułu ES w kontekście windowaplikacji internetowej, a także rejestracji pracownika usługi, który używa tego samego modułu 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);
    // ...
  })());
});

Zgodność wsteczna

Powyższy przykład działałby dobrze, gdyby wszystkie przeglądarki obsługiwały moduły ES w skryptach service worker, ale na razie jest inaczej.

Aby uwzględnić przeglądarki, które nie mają wbudowanego wsparcia, możesz uruchomić skrypt service workera za pomocą pakera zgodnego z modułami ES, aby utworzyć service workera, który zawiera cały kod modułu w postaci inline i będzie działać w starszych przeglądarkach. Jeśli moduły, które próbujesz zaimportować, są już dostępne w pakiecie w formatach IIFE lub UMD, możesz je zaimportować za pomocą narzędzia importScripts().

Gdy masz już 2 wersje usługi działającej w tle – jedną, która korzysta z modułów ES, a drugą, która z nich nie korzysta – musisz wykryć, co obsługuje bieżąca przeglądarka, i zarejestrować odpowiedni skrypt usługi działającej w tle. Sprawdzone metody wykrywania pomocy są obecnie w procesie zmian, ale możesz śledzić dyskusję w tym problemie na GitHubie, aby uzyskać rekomendacje.

_Zdjęcie autorstwa Vlado PaunovicUnsplash_