Domyślnie nowe mechanizmy Service Worker

tl;dr

Od Chrome 68 żądania HTTP, które sprawdzają dostępność aktualizacji skryptu service worker, nie będą już domyślnie realizowane przez pamięć podręczną HTTP. Jest to problem związany z częstym problemem deweloperów, który polega na tym, że ustawienie niezamierzonego nagłówka Cache-Control w skrypcie service worker może spowodować opóźnienia w aktualizacji.

Jeśli w przypadku skryptu /service-worker.js wyłączysz już buforowanie HTTP przez udostępnienie go za pomocą Cache-Control: max-age=0, nie zobaczysz żadnych zmian wynikających z nowego sposobu działania.

Dodatkowo od Chrome 78 porównanie bajtów do bajtów będzie stosowane do skryptów wczytywanych w skrypcie service worker przez importScripts(). Wszelkie zmiany wprowadzone w zaimportowanym skrypcie aktywują przebieg aktualizacji skryptu service worker, tak jak zmiana w skrypcie service worker najwyższego poziomu.

Wprowadzenie

Za każdym razem, gdy przechodzisz do nowej strony należącej do zakresu skryptu service worker, jawnie wywołujesz registration.update() z JavaScriptu lub gdy jest on „wybudzony” przez zdarzenie push lub sync, przeglądarka równolegle wysyła żądanie zasobu JavaScript, który został pierwotnie przekazany do wywołania navigator.serviceWorker.register(), w celu wyszukania aktualizacji skryptu skryptu service worker.

Na potrzeby tego artykułu zakładamy, że jego adres URL to /service-worker.js i że zawiera on pojedyncze wywołanie do funkcji importScripts(), które wczytuje dodatkowy kod, który jest uruchamiany w mechanizmie Service Worker:

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

// Other top-level code goes here.

Co się zmienia?

Przed wersją Chrome 68 żądanie aktualizacji /service-worker.js było wykonywane z pamięci podręcznej HTTP (tak jak w przypadku większości pobrań). Oznacza to, że jeśli skrypt został pierwotnie wysłany za pomocą funkcji Cache-Control: max-age=600, aktualizacje w ciągu najbliższych 600 sekund (10 minut) nie trafią do sieci, więc użytkownik może nie otrzymać najnowszej wersji skryptu service worker. Jeśli jednak wartość max-age będzie większa niż 86 400 (24 godziny), będzie traktowana tak, jakby była to wartość 86 400, aby zapobiec utknięciu na zawsze określonej wersji przez użytkowników.

Od wersji 68 pamięć podręczna HTTP będzie ignorowana podczas wysyłania żądań aktualizacji skryptu service worker, dlatego istniejące aplikacje internetowe mogą odnotować wzrost częstotliwości wysyłania takich żądań. Żądania wysyłane do importScripts będą nadal przesyłane przez pamięć podręczną HTTP. Jest to jednak ustawienie domyślne – dostępna jest nowa opcja rejestracji updateViaCache, która zapewnia kontrolę nad tym działaniem.

updateViaCache

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

Wartości te określają, czy i w jaki sposób standardowa pamięć podręczna HTTP przeglądarki jest włączana podczas wysyłania żądania HTTP w celu sprawdzenia zaktualizowanych zasobów skryptu service worker.

  • Gdy ustawisz wartość 'imports', pamięć podręczna HTTP nigdy nie będzie brana pod uwagę podczas sprawdzania dostępności aktualizacji skryptu /service-worker.js, ale będzie brana pod uwagę przy pobieraniu wszelkich zaimportowanych skryptów (w tym przykładzie path/to/import.js). Jest to wartość domyślna, która działa od wersji Chrome 68.

  • Gdy ustawisz wartość 'all', pamięć podręczna HTTP będzie brana pod uwagę przy wysyłaniu żądań dotyczących zarówno skryptu /service-worker.js najwyższego poziomu, jak i skryptów zaimportowanych wewnątrz mechanizmu Service Worker, np. path/to/import.js. Ta opcja odpowiada poprzedniemu działaniu Chrome sprzed wersji 68.

  • Gdy ustawisz wartość 'none', pamięć podręczna HTTP nie będzie brana pod uwagę podczas wysyłania żądań dotyczących /service-worker.js najwyższego poziomu ani żadnych zaimportowanych skryptów, takich jak hipotetyczna path/to/import.js.

Na przykład ten kod rejestruje skrypt service worker i zapewnia, że pamięć podręczna HTTP nie jest nigdy brana pod uwagę podczas sprawdzania aktualizacji skryptu /service-worker.js ani żadnych skryptów, do których odwołuje się importScripts() w /service-worker.js:

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

Sprawdza, czy są dostępne aktualizacje zaimportowanych skryptów

Przed wersją Chrome 78 każdy skrypt service worker wczytany przez importScripts() był pobierany tylko raz (najpierw sprawdzając go w pamięci podręcznej HTTP lub przez sieć, w zależności od konfiguracji updateViaCache). Po tym początkowym pobieraniu dane są zapisywane wewnętrznie przez przeglądarkę i nigdy nie są pobierane ponownie.

Jedynym sposobem na wymuszenie, aby zainstalowany już mechanizm Service Worker rozpoznawał zmiany w zaimportowanym skrypcie, jest zmiana adresu URL skryptu. Zazwyczaj można to zrobić przez dodanie wartości semver (np. importScripts('https://example.com/v1.1.0/index.js')) lub zawarcie skrótu zawartości (np. importScripts('https://example.com/index.abcd1234.js')). Skutkiem ubocznym zmiany zaimportowanego adresu URL jest zmiana zawartości skryptu aktualizacji skryptu usługi najwyższego poziomu.

Począwszy od Chrome 78, przy każdym sprawdzaniu aktualizacji pliku skryptu service worker najwyższego poziomu będą przeprowadzane jednocześnie testy w celu określenia, czy zawartość któregoś z zaimportowanych skryptów uległa zmianie. W zależności od użytych nagłówków Cache-Control zaimportowane skrypty mogą być przeprowadzane przez pamięć podręczną HTTP, jeśli updateViaCache ma wartość 'all' lub 'imports' (co jest wartością domyślną), albo testy mogą być kierowane bezpośrednio do sieci, jeśli wartość updateViaCache ma wartość 'none'.

Jeśli sprawdzanie aktualizacji zaimportowanego skryptu powoduje wystąpienie różnicy między bajtami a danymi zapisanymi wcześniej przez skrypt service worker, z kolei uruchamia się pełny proces aktualizacji zaimportowanego mechanizmu Service Worker, nawet jeśli plik mechanizmu Service Worker najwyższego poziomu pozostaje taki sam.

Działanie Chrome 78 odpowiada temu, co przeglądarka Firefox zaimplementowała kilka lat temu, w wersji 56. Safari już też stosuje takie działanie.

Co muszą zrobić deweloperzy?

Jeśli wyłączysz buforowanie HTTP w przypadku skryptu /service-worker.js, udostępniając go za pomocą parametru Cache-Control: max-age=0 (lub podobnej wartości), nie zobaczysz żadnych zmian w związku z nowym działaniem domyślnym.

Jeśli wyświetlasz skrypt /service-worker.js z włączonym buforowaniem HTTP (celowo lub dlatego, że jest to po prostu domyślne dla Twojego środowiska hostingu), możesz zauważyć napływ dodatkowych żądań HTTP dla /service-worker.js wysyłanych do Twojego serwera. Są to żądania, które były realizowane przez pamięć podręczną HTTP. Jeśli nadal chcesz zezwalać na to, aby wartość nagłówka Cache-Control wpływała na aktualność pliku /service-worker.js, musisz zacząć bezpośrednio ustawiać updateViaCache: 'all' podczas rejestrowania skryptu service worker.

W starszych wersjach przeglądarek użytkownicy mogą być użytkownikami z długiego ogona, dlatego warto nadal ustawiać nagłówek HTTP Cache-Control: max-age=0 w skryptach skryptu service worker, nawet jeśli nowsze przeglądarki mogą je ignorować.

Deweloperzy mogą wykorzystać tę możliwość, aby zdecydować, czy chcą wyraźnie wyłączyć teraz zaimportowane skrypty z buforowania HTTP, i w razie potrzeby dodać updateViaCache: 'none' do rejestracji skryptu service worker.

Udostępnianie zaimportowanych skryptów

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

Jeśli chcesz uniknąć tego dodatkowego ruchu HTTP, ustaw długotrwałe nagłówki Cache-Control podczas udostępniania skryptów zawierających semver lub hasze w adresach URL oraz używaj domyślnego działania updateViaCache ('imports').

Jeśli chcesz, aby zaimportowane skrypty były często sprawdzane pod kątem częstych aktualizacji, upewnij się, że udostępniasz je za pomocą funkcji Cache-Control: max-age=0 lub używasz metody updateViaCache: 'none'.

Więcej informacji

Artykuły „The Service Worker Lifecycle” oraz „Cacheing sprawdzone metody and max-age gotchas” (Jake Archibald) są polecane wszystkim deweloperom, którzy wdrażają wszystko w internecie.