Domyślnie nowe mechanizmy Service Worker

tl;dr

Od wersji Chrome 68 żądania HTTP, które sprawdzają dostępność aktualizacji skryptu skryptu service worker, nie będą już domyślnie realizowane przez pamięć podręczną HTTP. W ten sposób eliminuje to częste problemy deweloperów – ustawienie niezamierzonego nagłówka Cache-Control w skrypcie skryptu service worker może skutkować opóźnieniami w aktualizacjach.

Jeśli zrezygnujesz z buforowania HTTP skryptu /service-worker.js, udostępniając go za pomocą Cache-Control: max-age=0, nie zauważysz żadnych zmian wynikających z nowego działania domyślnego.

Dodatkowo od Chrome 78 porównanie bajtów na bajty będzie stosowane w przypadku skryptów wczytywanych przez skrypt service worker za pomocą narzędzia importScripts(). Każda zmiana w zaimportowanym skrypcie aktywuje proces aktualizacji skryptu service worker, podobnie jak zmiana w skrypcie service worker najwyższego poziomu.

Wprowadzenie

Za każdym razem, gdy otwierasz nową stronę znajdującą się w zakresie skryptu service worker, bezpośrednio wywołasz registration.update() z kodu JavaScript lub gdy mechanizm Service Worker zostanie „wybudzony” przez zdarzenie push lub sync, przeglądarka równolegle poprosi o zasób JavaScript przekazany pierwotnie do wywołania navigator.serviceWorker.register() w celu znalezienia aktualizacji skryptu service worker.

Na potrzeby tego artykułu załóżmy, że jego adres URL to /service-worker.js i że zawiera on jedno wywołanie importScripts(), które wczytuje dodatkowy kod uruchamiany w skrypcie service worker:

// Inside our /service-worker.js file:
importScripts('path/to/import.js');

// Other top-level code goes here.

Co się zmienia?

Przed Chrome 68 żądanie aktualizacji /service-worker.js było wysyłane za pomocą pamięci podręcznej HTTP (jak w przypadku większości pobrań). Oznaczało to, że jeśli skrypt został pierwotnie wysłany za pomocą Cache-Control: max-age=600, aktualizacje w ciągu najbliższych 600 sekund (10 minut) nie zostaną przekazane do sieci. Użytkownik może więc nie otrzymać najnowszej wersji mechanizmu Service Worker. Jeśli jednak max-age ma wartość większą niż 86 400 (24 godziny), jest traktowana tak, jakby była to 86 400, aby użytkownicy nie musieli utykać na określoną wersję na zawsze.

Od wersji 68 pamięć podręczna HTTP będzie ignorowana przy żądaniach aktualizacji skryptu skryptu service worker, więc istniejące aplikacje internetowe mogą zauważyć wzrost częstotliwości żądań ich skryptu. Żądania do importScripts będą nadal wysyłane przez pamięć podręczną HTTP. Jest to jednak tylko opcja domyślna – dostępna jest nowa opcja rejestracji, updateViaCache, która zapewnia kontrolę nad tym zachowaniem.

updateViaCache

Deweloperzy mogą teraz przekazywać przy wywoływaniu parametru navigator.serviceWorker.register() nową opcję: parametr updateViaCache. Przyjmuje jedną z 3 wartości: 'imports', 'all' lub 'none'.

Wartości określają, czy i jak standardowa pamięć podręczna HTTP przeglądarki bierze pod uwagę podczas wysyłania żądania HTTP w celu sprawdzenia zaktualizowanych zasobów skryptu service worker.

  • Gdy zasada ma wartość 'imports', pamięć podręczna HTTP nigdy nie jest sprawdzana podczas sprawdzania dostępności aktualizacji skryptu /service-worker.js, ale jest konsultowana podczas pobierania zaimportowanych skryptów (w naszym przykładzie path/to/import.js). Jest to ustawienie domyślne, które odpowiada działaniu w Chrome 68.

  • Gdy ustawisz wartość 'all', serwer będzie konsultowany z pamięci podręcznej HTTP podczas wysyłania żądań zarówno w przypadku skryptu /service-worker.js najwyższego poziomu, jak i wszelkich skryptów zaimportowanych do skryptu service worker, np. path/to/import.js. Ta opcja odpowiada wcześniejszemu działaniu w Chrome sprzed wersji 68.

  • Jeśli zasada ma wartość 'none', pamięć podręczna HTTP nie jest brana pod uwagę podczas wysyłania żądań /service-worker.js najwyższego poziomu ani żadnych zaimportowanych skryptów, takich jak hipotetyczny path/to/import.js.

Poniższy kod spowoduje na przykład zarejestrowanie skryptu service worker, który nie będzie sprawdzał aktualizacji pamięci podręcznej HTTP ani aktualizacji skryptu /service-worker.js, do którego odwołuje się skrypt importScripts() wewnątrz tagu /service-worker.js:

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/service-worker.js', {
    updateViaCache: 'none',
    // Optionally, set 'scope' here, if needed.
  });
}

Sprawdza, czy są aktualizacje zaimportowanych skryptów

Przed Chrome 78 każdy skrypt service worker załadowany przez importScripts() był pobierany tylko raz (sprawdzając najpierw pamięć podręczną HTTP lub przez sieć, w zależności od konfiguracji updateViaCache). Po początkowym pobraniu są one przechowywane wewnętrznie przez przeglądarkę i nigdy nie są ponownie pobierane.

Jedynym sposobem na wymuszenie już zainstalowanego skryptu service worker do pobrania zmian w zaimportowanym skrypcie była zmiana adresu URL skryptu. Zwykle wystarczy dodać wartość semver (np. importScripts('https://example.com/v1.1.0/index.js')) lub dodać hasz treści (np. importScripts('https://example.com/index.abcd1234.js')). Efektem ubocznym zmiany zaimportowanego adresu URL jest zmiana adresu URL skryptu najwyższego poziomu, która z kolei uruchamia zmianę zawartości skryptu aktualizacji.

Od wersji Chrome 78 za każdym razem, gdy sprawdzana jest dostępność aktualizacji pliku skryptu service worker najwyższego poziomu, są one wykonywane w tym samym czasie w celu określenia, czy treść zaimportowanych skryptów uległa zmianie. W zależności od użytych nagłówków Cache-Control te operacje sprawdzania skryptów mogą być wykonywane przez pamięć podręczną HTTP, jeśli zasada updateViaCache ma wartość 'all' lub 'imports' (czyli wartość domyślną). Jeśli zasada updateViaCache ma wartość 'none', testy mogą być kierowane bezpośrednio na sieć.

Jeśli po sprawdzeniu aktualizacji zaimportowanego skryptu nastąpi różnica w bajtach w porównaniu z danymi zapisanymi wcześniej przez skrypt service worker, nawet jeśli plik skryptu service worker najwyższego poziomu pozostanie niezmieniony.

Sposób działania Chrome w wersji 78 jest taki sam jak ten zaimplementowany kilka lat temu w Firefoksie w wersji 56. Te funkcje są już stosowane w Safari.

Co muszą zrobić deweloperzy?

Jeśli zrezygnujesz z buforowania zawartości HTTP w przypadku skryptu /service-worker.js, udostępniając go za pomocą parametru Cache-Control: max-age=0 (lub podobnej wartości), nie zauważysz żadnych zmian z powodu nowego domyślnego sposobu działania.

Jeśli udostępniasz skrypt /service-worker.js z włączonym buforowaniem HTTP – celowo lub dlatego, że jest to ustawienie domyślne w Twoim środowisku hostingowym, możesz zauważyć wzrost liczby dodatkowych żądań HTTP do /service-worker.js wysyłanych do Twojego serwera. Są to żądania, które wcześniej były wypełniane przez pamięć podręczną HTTP. Jeśli nadal chcesz, aby wartość nagłówka Cache-Control wpływała na aktualność /service-worker.js, musisz zacząć jawnie ustawiać updateViaCache: 'all' przy rejestrowaniu skryptu service worker.

Biorąc pod uwagę, że użytkownicy starszych wersji przeglądarek mogą spędzać dużo czasu, warto nadal ustawiać nagłówek HTTP Cache-Control: max-age=0 w skryptach service worker, mimo że nowsze przeglądarki mogą je ignorować.

Deweloperzy mogą dzięki tej możliwości zdecydować, czy chcą od razu wyraźnie zrezygnować z buforowania zawartości pamięci podręcznej HTTP przez zaimportowane skrypty i w razie potrzeby dodać updateViaCache: 'none' do rejestracji mechanizmów Service Worker.

Wyświetlanie zaimportowanych skryptów

Począwszy od Chrome 78 deweloperzy mogą zauważyć więcej przychodzących żądań HTTP dotyczących zasobów wczytywanych przez interfejs importScripts(), ponieważ będą one teraz sprawdzane pod kątem dostępności aktualizacji.

Aby uniknąć tego dodatkowego ruchu HTTP, ustaw długotrwałe nagłówki Cache-Control podczas udostępniania skryptów, które w adresach URL zawierają semver lub hasze, i wykorzystaj domyślne zachowanie updateViaCache, które ma wartość 'imports'.

Jeśli chcesz, by zaimportowane skrypty były często sprawdzane pod kątem częstych aktualizacji, pamiętaj o udostępnianiu ich za pomocą protokołu Cache-Control: max-age=0 lub updateViaCache: 'none'.

Więcej informacji

Artykuły „The Service Worker Lifecycle” (Cykl życia instancji Service Worker) i „Buforowanie sprawdzone metody i gotowe ustawienia maksymalnej wieku” zostały napisane przez Jake Archibalda dla wszystkich deweloperów, którzy wdrażają cokolwiek w internecie.