Service Worker to specjalny skrypt JavaScript działający w tle przeglądarki, pełniący rolę pośrednika (proxy) między aplikacją webową a siecią. Umożliwia m.in. pracę offline, zaawansowane cache’owanie, powiadomienia push i synchronizację w tle w progresywnych aplikacjach webowych (PWA).
W PWA to właśnie Service Worker jest „silnikiem” niezawodności i szybkości – dzięki niemu doświadczenie webowe może zbliżać się do aplikacji natywnych.
PWA w skrócie – gdzie w tym wszystkim jest service worker?
Progresywne aplikacje webowe (Progressive Web Apps, PWA) to strony/aplikacje WWW, które:
- działają w przeglądarce, ale zachowują się jak aplikacje natywne (ikona na ekranie, pełnoekranowy tryb, splash screen),
- są szybkie, niezawodne i responsywne na różnych urządzeniach,
- oferują funkcje offline, powiadomienia push oraz instalację na pulpicie użytkownika.
Typowe filary PWA to:
- plik manifestu – opisuje nazwę aplikacji, ikonę, kolorystykę, URL startowy i tryb wyświetlania;
- Service Worker – skrypt działający w tle, odpowiadający za cache, offline, push, synchronizację itp.;
- model app shell – struktura aplikacji cache’owana w przeglądarce, a treść ładowana dynamicznie.
To Service Worker „odblokowuje” najważniejsze funkcje PWA – tryb offline, strategie cache’owania, odporność na niestabilne łącza i powiadomienia.
Czym dokładnie jest service worker?
Najkrótsza, praktyczna definicja:
Service Worker to skrypt JavaScript działający w tle przeglądarki, niezależnie od strony, który przechwytuje żądania sieciowe i decyduje, czy skorzystać z sieci, czy z lokalnego cache.
Kluczowe cechy:
- to skrypt JS uruchamiany w oddzielnym wątku – nie działa bezpośrednio w kontekście strony,
- działa w tle, niezależnie od tego, czy karta z twoją stroną jest aktywna,
- pełni rolę wirtualnego proxy między przeglądarką a siecią,
- ma dostęp do Cache Storage API, dzięki czemu może przechowywać w pamięci podręcznej HTML, CSS, JS, obrazy i odpowiedzi API,
- może realizować funkcje takie jak powiadomienia push i synchronizacja w tle,
- nie ma bezpośredniego dostępu do DOM – komunikuje się z aplikacją np. przez
postMessage.
Dzięki temu mechanizmowi możesz programistycznie zdefiniować, jak aplikacja zachowa się przy braku internetu, wolnym łączu czy kolejnej wizycie użytkownika.
Jak działa service worker krok po kroku?
Ogólny model działania
Gdy aplikacja żąda zasobu (np. /styles.css, /api/products, /index.html) w zakresie działania Service Workera (scope), worker:
- przechwytuje żądanie jako zdarzenie
fetch; - analizuje je według zdefiniowanej logiki (np. „najpierw cache, potem sieć”);
- decyduje, czy:
- zwrócić zasób z cache przez Cache Storage API,
- przekazać żądanie do sieci, jakby Service Workera nie było,
- wygenerować odpowiedź lokalnie, np. komunikat „jesteś offline”.
Dzięki temu twoja PWA może:
- działać w pełni lub częściowo offline, korzystając z lokalnie przechowywanych zasobów,
- szybciej się ładować, bo część zasobów pochodzi z cache, nie z sieci,
- zachowywać się przewidywalnie nawet przy niestabilnym lub bardzo wolnym łączu.
Życie service workera – rejestracja, instalacja, aktywacja
W przeciwieństwie do zwykłego JS na stronie, Service Worker ma z góry zdefiniowany cykl życia:
- Rejestracja (
navigator.serviceWorker.register(...)) – wykonywana z poziomu strony; - Instalacja (
install) – worker pobiera się i uruchamia pierwszy raz, zwykle cache’ując kluczowe zasoby (app shell); - Aktywacja (
activate) – worker zaczyna obsługiwać żądania w swoim scope, może też „posprzątać” stary cache; - Obsługa zdarzeń – np.
fetch,push,sync,message– worker budzi się tylko na czas obsługi zdarzenia.
Przeglądarki celowo utrzymują krótki czas życia instancji Service Workera – worker startuje wraz ze zdarzeniem, działa tak krótko, jak to konieczne, po czym jest usypiany. Chroni to zasoby urządzenia i baterię.
Rejestracja service workera w praktyce
Podstawowa rejestracja (np. w main.js):
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker
.register('/service-worker.js')
.then(registration => {
console.log('Service Worker zarejestrowany:', registration.scope);
})
.catch(error => {
console.error('Błąd rejestracji Service Workera:', error);
});
});
}
Tak zarejestrowany plik /service-worker.js zostanie pobrany i zainstalowany przy pierwszej wizycie użytkownika.
Obejmie swoim zakresem (scope) wszystkie zasoby znajdujące się w tym samym katalogu i niżej (np. / dla całej domeny).
Rejestracja jest fundamentem – bez niej PWA pozostanie zwykłą stroną, nawet jeśli masz manifest.
Przykładowy service worker – cache’owanie przy instalacji i obsługa fetch
Przykład minimalnego Service Workera realizującego prostą strategię cache-first dla statycznych zasobów:
const CACHE_NAME = 'app-cache-v1';
const ASSETS = [
'/',
'/index.html',
'/styles.css',
'/app.js',
'/images/logo.png'
];
// 1. Instalacja – wstępne cache’owanie zasobów (app shell)
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME).then(cache => cache.addAll(ASSETS))
);
});
// 2. Aktywacja – sprzątanie starych cache’y
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(keys =>
Promise.all(keys
.filter(key => key !== CACHE_NAME)
.map(key => caches.delete(key))
)
)
);
});
// 3. Obsługa fetch – strategia cache-first
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(cachedResponse => {
if (cachedResponse) {
return cachedResponse; // z cache
}
return fetch(event.request); // z sieci
})
);
});
Podczas instalacji cache’ujesz kluczowe zasoby, by aplikacja mogła działać offline. W obsłudze fetch worker przechwytuje żądanie i decyduje, czy odpowiedzieć z cache, czy z sieci.
Typowe zastosowania service workera w PWA
Praca offline i offline-first
Service Worker jest „sercem i mózgiem PWA”, jeśli chodzi o tryb offline. Dzięki niemu wdrożysz strategię offline-first lub cache-first, w której aplikacja najpierw próbuje odpowiedzieć z cache, a sieć traktuje jako źródło uzupełniające.
Efekt: użytkownik ma dostęp do kluczowych zasobów nawet bez internetu, a aplikacja działa stabilnie w warunkach słabego zasięgu (np. w pociągu lub w terenie).
Przyspieszenie ładowania
Cache’owanie HTML, CSS, JS, obrazów czy odpowiedzi API w Cache Storage sprawia, że kolejne wizyty korzystają z lokalnych zasobów zamiast wszystkiego pobierać z serwera. Zyskujesz lepszy Time To Interactive i realnie niższe zużycie transferu.
To ważne także z perspektywy dostępności – dla osób z limitowanym pakietem danych czy wolnym łączem mniejsza liczba żądań do sieci to wymierna korzyść.
Powiadomienia push
Service Worker obsługuje powiadomienia push, odbierane nawet wtedy, gdy strona nie jest otwarta. Mogą informować np. o nowych wiadomościach, zmianie statusu zamówienia czy aktualizacjach treści, a worker w reakcji na zdarzenie push wyświetla powiadomienie i obsługuje interakcje.
Synchronizacja w tle (background sync)
Service Worker pozwala realizować synchronizację w tle – np. zapisywać dane lokalnie, gdy użytkownik jest offline, i wysłać je do serwera, gdy połączenie wróci. To kluczowe w aplikacjach terenowych, raportowych, notatkowych czy ankietowych.
Strategie cache’owania z service workerem
Nie wystarczy „cokolwiek wrzucić do cache”. Trzeba świadomie dobrać strategię cache’owania do rodzaju zasobów. Najpopularniejsze podejścia to:
- Cache-first – najpierw odpowiedź z cache; jeśli zasobu brakuje, dopiero wtedy sieć; dobre dla statycznych elementów rzadko się zmieniających (ikony, fonty);
- Network-first – najpierw próba z sieci, a w razie błędu fallback do cache; sprawdza się dla dynamicznych danych (np. aktualne API);
- Stale-while-revalidate – błyskawiczna odpowiedź z cache i równoległe odświeżenie z sieci; łączy szybkość z aktualnością;
- Offline-first – ważne elementy dostępne w pełni offline, z fallbackiem dla treści krytycznych.
Te strategie można komponować następująco:
- HTML aplikacji – network-first z fallbackiem do cache,
- statyczne assety – cache-first,
- API – stale-while-revalidate.
Service Worker to miejsce, w którym implementujesz te reguły w kodzie.
Ograniczenia i bezpieczeństwo
Brak dostępu do DOM
Service Worker nie ma bezpośredniego dostępu do DOM ani globalnych zmiennych strony. Komunikacja odbywa się np. przez postMessage lub przez persystencję w IndexedDB/Cache Storage i ponowne odczytanie danych po stronie aplikacji.
Konieczność bezpiecznego połączenia (HTTPS)
Service Workery działają wyłącznie na bezpiecznych originach (HTTPS) – wyjątkiem jest localhost używany w trakcie developmentu. Powód: worker przechwytuje żądania i może modyfikować odpowiedzi, więc musi działać w zaufanym, szyfrowanym kontekście.
Zakres działania (scope)
Service Worker działa tylko w obrębie swojego zakresu (scope) – zwykle katalogu, w którym znajduje się plik, oraz wszystkiego poniżej.
Jeśli worker jest pod /app/service-worker.js, obejmie /app/*, ale nie /blog/*. Aby objąć całą domenę, umieść go w katalogu głównym (np. /service-worker.js).
Aktualizacje i wersjonowanie
Gdy zmieniasz plik Service Workera:
- przeglądarka wykrywa nową wersję i próbuje ją zainstalować równolegle do starej,
- nowy worker przechodzi do stanu
waiting, dopóki wszystkie karty korzystające ze starego nie zostaną zamknięte, - dopiero potem staje się
activated.
Dlatego ważne jest:
- wersjonowanie cache’y (np.
app-cache-v1,app-cache-v2), - świadome czyszczenie starych cache’y w
activate, - rozważne używanie
self.skipWaiting()iclients.claim(), by nie przerywać użytkownikowi sesji.
Service worker a dostępność (a11y) i inkluzywne projektowanie
Offline jako element dostępności
Dostępność cyfrowa dotyczy wszystkich użytkowników, także w zmiennych warunkach:
- ograniczony lub drogi internet,
- niestabilne połączenie (np. w pociągu),
- urządzenia o niskiej mocy.
Zapewnienie dostępu offline do kluczowych treści realnie zwiększa dostępność serwisu. Przykładowo:
- aplikacje edukacyjne pozwalają raz pobrać materiały i czytać je offline,
- treści informacyjne (instrukcje, komunikaty krytyczne) są dostępne bez sieci,
- formularze można wypełnić offline i wysłać później (background sync).
Komunikaty o trybie offline i błędach
Brak internetu nie może kończyć się pustym ekranem ani niezrozumiałym błędem. Service Worker może zwrócić przyjazną stronę „offline fallback” ze zrozumiałą informacją o sytuacji.
Taka strona powinna:
- mieć poprawną strukturę semantyczną (nagłówki, listy, landmarki), by była zrozumiała dla czytników ekranu,
- zawierać jasny komunikat, co się stało („Brak połączenia z internetem. Część treści może być niedostępna.”),
- oferować opcje działania: np. „Spróbuj ponownie”, „Zobacz ostatnio zapisane dane”.
Progresywne ulepszanie
Strona powinna działać także bez Service Workera – jako „zwykły” serwis. Worker jedynie ulepsza doświadczenie i nie może blokować dostępu do treści.
To szczególnie ważne dla starszych urządzeń, niszowych przeglądarek i w kontekście wymagań dostępności, gdzie treści muszą być dostępne w podstawowy sposób nawet bez zaawansowanych funkcji.
Dobre praktyki implementacyjne
Kilka praktycznych rekomendacji dla zespołów tworzących PWA:
- zacznij od małego scope’u – na start cache’uj statyczne zasoby (app shell), a dopiero potem rozbudowuj obsługę API i tryb offline,
- wersjonuj cache i Service Workera – zmieniaj nazwy cache’y (np.
v1,v2) i czyść stare wactivate, by nie gromadzić nieużywanych danych, - obsługuj błędy sieciowe z sensem – nie zakładaj, że sieć zawsze działa; twórz fallbacki offline, czytelne komunikaty i logikę na wypadek cząstkowego braku danych,
- pamiętaj o bezpieczeństwie – serwuj PWA po HTTPS, waliduj dane z sieci, nie cache’uj wrażliwych informacji (np. danych osobowych, tokenów) i używaj nagłówków HTTP ograniczających cache tam, gdzie to konieczne,
- testuj w narzędziach developerskich – skorzystaj z DevTools (np. w Chrome) do debugowania Service Workera, przeglądania cache i symulacji offline,
- rozważ użycie bibliotek (np. Workbox) – w większych projektach ułatwią zarządzanie strategiami cache i aktualizacjami,
- projektuj z myślą o dostępności – upewnij się, że:
- aplikacja działa choćby w ograniczonym zakresie bez Service Workera,
- komunikaty o offline i błędach są semantyczne, zrozumiałe i dostępne dla czytników ekranu,
- kluczowe treści można przewidywalnie zapisać do użycia offline.
to podstawa.






