tl;dr
Vanaf Chrome 68 worden HTTP-verzoeken die controleren op updates voor het service worker-script niet langer standaard door de HTTP-cache uitgevoerd. Dit omzeilt een veelvoorkomend pijnpunt voor ontwikkelaars , waarbij het instellen van een onbedoelde Cache-Control
header op uw service worker-script tot vertraagde updates kan leiden.
Als u zich al heeft afgemeld voor HTTP-caching voor uw /service-worker.js
door het aan te bieden met Cache-Control: max-age=0
, dan zou u geen wijzigingen moeten zien vanwege het nieuwe standaardgedrag.
Bovendien wordt vanaf Chrome 78 de byte-voor-byte-vergelijking toegepast op scripts die in een servicemedewerker zijn geladen via importScripts()
. Elke wijziging die in een geïmporteerd script wordt aangebracht, zal de updatestroom van de servicemedewerker activeren, net zoals een wijziging aan de servicemedewerker op het hoogste niveau dat zou doen.
Achtergrond
Elke keer dat u naar een nieuwe pagina navigeert die onder het bereik van een servicemedewerker valt, roept u registration.update()
expliciet op vanuit JavaScript, of wanneer een servicemedewerker wordt "gewekt" via een push
of sync
, zal de browser parallel hieraan vragen de JavaScript-bron die oorspronkelijk is doorgegeven aan de navigator.serviceWorker.register()
, om te zoeken naar updates voor het service worker-script.
Laten we voor de doeleinden van dit artikel aannemen dat de URL /service-worker.js
is en dat deze een enkele aanroep naar importScripts()
bevat, die aanvullende code laadt die in de service worker wordt uitgevoerd:
// Inside our /service-worker.js file:
importScripts('path/to/import.js');
// Other top-level code goes here.
Wat verandert er?
Vóór Chrome 68 werd het updateverzoek voor /service-worker.js
gedaan via de HTTP-cache (zoals bij de meeste ophaalacties). Dit betekende dat als het script oorspronkelijk met Cache-Control: max-age=600
, updates binnen de volgende 600 seconden (10 minuten) niet naar het netwerk zouden gaan, waardoor de gebruiker mogelijk niet de meest up-to-date versie ontvangt van de servicemedewerker. Als max-age
echter groter is dan 86400 (24 uur), wordt dit behandeld alsof het 86400 is, om te voorkomen dat gebruikers voor altijd aan een bepaalde versie vastzitten.
Vanaf 68 wordt de HTTP-cache genegeerd bij het aanvragen van updates voor het service worker-script, waardoor bestaande webapplicaties mogelijk een toename zien in de frequentie van aanvragen voor hun service worker-script. Aanvragen voor importScripts
gaan nog steeds via de HTTP-cache. Maar dit is slechts de standaard: er is een nieuwe registratieoptie, updateViaCache
, beschikbaar die controle over dit gedrag biedt.
updateViaCache
Ontwikkelaars kunnen nu een nieuwe optie doorgeven bij het aanroepen van navigator.serviceWorker.register()
: de parameter updateViaCache
. Er zijn drie waarden nodig: 'imports'
, 'all'
of 'none'
.
De waarden bepalen of en hoe de standaard HTTP-cache van de browser een rol speelt bij het maken van het HTTP-verzoek om te controleren op bijgewerkte servicemedewerkerbronnen.
Wanneer ingesteld op
'imports'
, zal de HTTP-cache nooit worden geraadpleegd bij het controleren op updates voor het script/service-worker.js
, maar wel bij het ophalen van geïmporteerde scripts (path/to/import.js
in ons voorbeeld) . Dit is de standaard en komt overeen met het gedrag vanaf Chrome 68.Wanneer ingesteld op
'all'
, wordt de HTTP-cache geraadpleegd bij het indienen van verzoeken voor zowel het script/service-worker.js
op het hoogste niveau, als voor alle scripts die in de service worker worden geïmporteerd, zoalspath/to/import.js
. Deze optie komt overeen met het eerdere gedrag in Chrome, vóór Chrome 68.Wanneer ingesteld op
'none'
, wordt de HTTP-cache niet geraadpleegd bij het indienen van verzoeken voor het hoogste niveau/service-worker.js
of voor geïmporteerde scripts, zoals het hypothetischepath/to/import.js
.
De volgende code registreert bijvoorbeeld een servicemedewerker en zorgt ervoor dat de HTTP-cache nooit wordt geraadpleegd bij het controleren op updates voor het script /service-worker.js
of voor scripts waarnaar wordt verwezen via importScripts()
in /service-worker.js
:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js', {
updateViaCache: 'none',
// Optionally, set 'scope' here, if needed.
});
}
Controleert op updates voor geïmporteerde scripts
Vóór Chrome 78 werd elk servicewerknemerscript dat via importScripts()
werd geladen, slechts één keer opgehaald (eerst gecontroleerd aan de hand van de HTTP-cache of via het netwerk, afhankelijk van de updateViaCache
configuratie). Na het eerste ophalen zou het intern door de browser worden opgeslagen en nooit opnieuw worden opgehaald.
De enige manier om een reeds geïnstalleerde servicemedewerker te dwingen wijzigingen in een geïmporteerd script op te halen, was door de URL van het script te wijzigen, meestal door een semver-waarde toe te voegen (bijvoorbeeld importScripts('https://example.com/v1.1.0/index.js')
) of door een hash van de inhoud op te nemen (bijvoorbeeld importScripts('https://example.com/index.abcd1234.js')
). Een neveneffect van het wijzigen van de geïmporteerde URL is dat de inhoud van het service worker-script op het hoogste niveau verandert, wat op zijn beurt de updatestroom voor de service worker activeert.
Vanaf Chrome 78 wordt elke keer dat er een updatecontrole wordt uitgevoerd voor een servicemedewerkerbestand op het hoogste niveau, tegelijkertijd gecontroleerd of de inhoud van geïmporteerde scripts al dan niet is gewijzigd. Afhankelijk van de gebruikte Cache-Control
headers kunnen deze geïmporteerde scriptcontroles worden vervuld door de HTTP-cache als updateViaCache
is ingesteld op 'all'
of 'imports'
(wat de standaardwaarde is), of kunnen de controles rechtstreeks tegen het netwerk ingaan als updateViaCache
is ingesteld op 'none'
.
Als een updatecontrole voor een geïmporteerd script resulteert in een byte-voor-byte verschil met wat eerder door de servicemedewerker is opgeslagen, zal dat op zijn beurt de updatestroom voor de volledige servicemedewerker activeren, zelfs als het servicemedewerkerbestand op het hoogste niveau blijft staan hetzelfde.
Het gedrag van Chrome 78 komt overeen met wat Firefox enkele jaren geleden implementeerde in Firefox 56. Safari implementeert dit gedrag ook al.
Wat moeten ontwikkelaars doen?
Als u zich effectief heeft afgemeld voor HTTP-caching voor uw /service-worker.js
door het aan te bieden met Cache-Control: max-age=0
(of een vergelijkbare waarde), dan zou u geen wijzigingen moeten zien vanwege het nieuwe standaardgedrag.
Als u uw /service-worker.js
aanbiedt met HTTP-caching ingeschakeld, hetzij opzettelijk, hetzij omdat dit gewoon de standaard is voor uw hostingomgeving , kunt u een toename zien van extra HTTP-verzoeken voor /service-worker.js
die tegen uw server: dit zijn verzoeken die vroeger werden vervuld door de HTTP-cache. Als u wilt blijven toestaan dat de Cache-Control
headerwaarde de versheid van uw /service-worker.js
beïnvloedt, moet u updateViaCache: 'all'
expliciet instellen bij het registreren van uw servicemedewerker.
Gezien het feit dat er mogelijk een lange reeks gebruikers is in oudere browserversies, is het nog steeds een goed idee om door te gaan met het instellen van de Cache-Control: max-age=0
HTTP-header op service worker-scripts, ook al negeren nieuwere browsers deze.
Ontwikkelaars kunnen deze mogelijkheid gebruiken om te beslissen of ze hun geïmporteerde scripts nu expliciet willen afmelden voor HTTP-caching, en indien nodig updateViaCache: 'none'
aan hun servicemedewerkerregistratie willen toevoegen.
Geïmporteerde scripts serveren
Vanaf Chrome 78 zien ontwikkelaars mogelijk meer inkomende HTTP-verzoeken voor bronnen die zijn geladen via importScripts()
, omdat ze nu worden gecontroleerd op updates.
Als u dit extra HTTP-verkeer wilt vermijden, stelt u Cache-Control
headers met een lange levensduur in bij het weergeven van scripts die semver of hashes in hun URL's bevatten, en vertrouwt u op het standaard updateViaCache
gedrag van 'imports'
.
Als u wilt dat uw geïmporteerde scripts worden gecontroleerd op frequente updates, zorg er dan voor dat u ze ofwel aanbiedt met Cache-Control: max-age=0
, of dat u updateViaCache: 'none'
gebruikt.
Verder lezen
" The Service Worker Lifecycle " en " Caching best practices & max-age valkuilen ", beide door Jake Archibald, zijn aanbevolen lectuur voor alle ontwikkelaars die iets op het web implementeren.