Moduły ES w skryptach service worker

Nowoczesna alternatywa dla funkcji importScripts().

Wprowadzenie

Moduły ES już od jakiegoś czasu są ulubionymi programistami. 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 zaczynamy udostępniać coraz szerzej obsługę importowania modułów ES w skrypcie service worker przeglądarki.

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.

Przykłady zastosowań

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 modułami ES polegała na użyciu starszych „uniwersalnych” formatów modułów, takich jak UMD, które zawierają niepotrzebne stałe elementy, oraz napisanie kodu wprowadzającego zmiany w zmiennych widocznych globalnie.

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 importy statyczne

Moduły ES można importować 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 importScripts() nie działają w skrypcie service worker, a wszystkie wywołania importScripts(), które są z natury synchroniczne, muszą zostać zakończone, zanim zakończy się faza 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.

W przyszłości to ograniczenie może zostać zniesione, a może być dozwolone dynamiczne importowanie modułów ES. Na razie używaj tylko składni statycznej wewnątrz skryptu service worker.

Co z innymi pracownikami?

Obsługa modułów ES w „dedykowanych” instancjach roboczych (utworzonych za pomocą new Worker('...', {type: 'module'})) jest szersza i jest obsługiwana w Chrome i Edge od wersji 80, a także w najnowszych wersjach Safari. Zarówno statyczne, jak i dynamiczne importowanie modułów ES jest obsługiwane przez dedykowane instancje robocze.

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 importowania map

Importowanie map umożliwia środowiskom wykonawczym przepisywanie specyfikatorów modułów, np. dołączanie na początku adresu URL preferowanej sieci CDN, z której mogą być ładowane 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ługiwane przeglądarki

Moduły ES w mechanizmach Service Worker są obsługiwane w Chrome i Edge od wersji 91.

Safari dodało obsługę w wersji przedpremierowej technologii 122. W przyszłości deweloperzy mogą spodziewać się udostępnienia tej funkcji w stabilnej wersji Safari.

Przykładowy kod

Oto podstawowy przykład wykorzystania udostępnionego modułu ES w kontekście window aplikacji internetowej przy jednoczesnym rejestrowaniu skryptu service worker, który korzysta z 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 dostosować się do przeglądarek, które nie mają wbudowanej obsługi, możesz uruchomić skrypt skryptu service worker za pomocą pakietu pakującego zgodnego z modułem ES, aby utworzyć mechanizm Service Worker, który zawiera wbudowany kod modułu i będzie działać w starszych przeglądarkach. Jeśli moduły, które próbujesz zaimportować, są już dostępne w pakietach w formatach IIFE lub UMD, możesz je zaimportować za pomocą narzędzia importScripts().

Gdy będą dostępne 2 wersje skryptu service worker – jedna korzysta z modułów ES i druga nie – musisz wykryć funkcje obsługiwane przez bieżącą przeglądarkę i zarejestrować odpowiedni skrypt skryptu service worker. Sprawdzone metody wykrywania pomocy są obecnie zmieniane, ale możesz zapoznać się z opisem w tym artykule na stronie GitHub, aby uzyskać rekomendacje.

_Zdjęcie: Vlado Paunovic, Unsplash_