Moduły ES w skryptach service worker

Nowoczesna alternatywa dla importScripts().

Tło

Moduły ES od dłuższego czasu cieszą się popularnością wśród deweloperów. Oprócz wielu innych korzyści oferują one uniwersalny format modułu, w którym udostępniony kod można opublikować raz i uruchamiać w przeglądarkach oraz w alternatywnych środowiskach wykonawczych, takich jak Node.js. Chociaż wszystkie nowoczesne przeglądarki obsługują moduły ES, nie wszystkie obsługują je wszędzie, gdzie można uruchomić kod. W szczególności obsługa importowania modułów ES w skrypcie service worker przeglądarki dopiero zaczyna być szerzej dostępna.

W tym artykule opisujemy aktualny stan obsługi modułów ES w skryptach service worker w popularnych przeglądarkach, a także pułapki, których należy unikać, oraz sprawdzone metody dostarczania kodu skryptu service worker zgodnego wstecznie.

Przypadki użycia

Idealnym przypadkiem użycia modułów ES w skryptach service worker jest wczytywanie nowoczesnej biblioteki lub kodu konfiguracji, który jest udostępniany innym środowiskom wykonawczym obsługującym moduły ES.

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

Skrypty importowane za pomocą modułów ES mogą wywołać proces aktualizacji skryptu service worker, jeśli ich zawartość ulegnie zmianie, co odpowiada zachowaniu funkcji importScripts().

Obecne ograniczenia

Tylko importy statyczne

Moduły ES można importować na 2 sposoby: statycznie przy użyciu składni import ... from '...' lub dynamicznie przy użyciu metody import(). W skrypcie service worker obecnie obsługiwana jest tylko składnia statyczna.

To ograniczenie jest analogiczne do podobnego ograniczenia dotyczącego korzystania z importScripts(). Dynamiczne wywołania importScripts() nie działają w skrypcie service worker, a wszystkie wywołania importScripts(), które są z natury synchroniczne, muszą zostać zakończone, zanim skrypt service worker zakończy fazę install. Dzięki temu ograniczeniu przeglądarka wie o całym kodzie JavaScriptu potrzebnym do implementacji skryptu service worker podczas instalacji i może go niejawnie zapisać w pamięci podręcznej.

To ograniczenie może zostać zniesione, a dynamiczny import modułów ES może być dozwolony. Na razie upewnij się, że używasz tylko składni statycznej w skrypcie service worker.

A co z innymi pracownikami?

Obsługa modułów ES w „dedykowanych” skryptach worker – utworzonych za pomocą new Worker('...', {type: 'module'}) – jest bardziej powszechna i jest dostępna w Chrome i Edge od wersji 80, a także w najnowszych wersjach Safari. W dedykowanych skryptach service worker obsługiwany jest zarówno statyczny, jak i dynamiczny import modułów ES.

Chrome i Edge obsługują moduły ES we współdzielonych skryptach service worker od wersji 83, ale obecnie żadna inna przeglądarka nie oferuje takiej obsługi.

Brak obsługi map importu

Mapy importu umożliwiają środowiskom wykonawczym przepisywanie specyfikatorów modułów, na przykład przez dodanie na początku adresu URL preferowanej sieci CDN, z której można wczytywać moduły ES.

Chociaż Chrome i Edge w wersji 89 i nowszych obsługują mapy importu, obecnie nie można ich używać z skryptami service worker.

Obsługa przeglądarek

Moduły ES w skryptach service worker są obsługiwane w Chrome i Edge od wersji 91.

Safari dodało obsługę w wersji Technology Preview 122, a programiści 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 window aplikacji internetowej, a także rejestrowania skryptu service worker, 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 w chwili pisania tego artykułu tak nie jest.

Aby dostosować skrypt do przeglądarek, które nie mają wbudowanej obsługi, możesz uruchomić skrypt skryptu service worker za pomocą pakietu zgodnego z modułem ES, aby utworzyć skrypt service worker, który zawiera cały kod modułu w tekście 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 formacie IIFE lub UMD, możesz je zaimportować za pomocą importScripts().

Gdy masz już dostępne 2 wersje skryptu service worker – jedną, która używa modułów ES, i drugą, która ich nie używa – musisz wykryć, co obsługuje bieżąca przeglądarka, i zarejestrować odpowiedni skrypt service worker. Sprawdzone metody wykrywania obsługi są obecnie w trakcie opracowywania, ale możesz śledzić dyskusję na temat rekomendacji w tym problemie na GitHubie.