tl;dr
A partire da Chrome 68, le richieste HTTP che verificano la presenza di aggiornamenti dello script del service worker non verranno più soddisfatte dalla cache HTTP per impostazione predefinita. Questa operazione risolve un problema comune degli sviluppatori, per cui l'impostazione di un'intestazione Cache-Control
involontaria nello script del service worker potrebbe causare aggiornamenti ritardati.
Se hai già disattivato la memorizzazione nella cache HTTP per lo script /service-worker.js
pubblicandolo
con Cache-Control: max-age=0
, non dovresti notare alcuna modifica a causa del nuovo
comportamento predefinito.
Inoltre, a partire da Chrome 78, il confronto byte per byte verrà applicato agli script caricati in un service worker tramite importScripts()
.
Qualsiasi modifica apportata a uno script importato attiverà il
flusso di aggiornamento del service worker,
proprio come farebbe una modifica al service worker di primo livello.
Contesto
Ogni volta che accedi a una nuova pagina nell'ambito di un service worker, chiami esplicitamente registration.update()
da JavaScript o quando un service worker viene "attivato" tramite un evento push
o sync
, il browser, in parallelo, richiederà la risorsa JavaScript passata in origine alla chiamata navigator.serviceWorker.register()
per cercare aggiornamenti dello script del service worker.
Ai fini di questo articolo, supponiamo che il suo URL sia /service-worker.js
e che contenga una singola chiamata a importScripts()
, che carica un codice aggiuntivo eseguito all'interno del service worker:
// Inside our /service-worker.js file:
importScripts('path/to/import.js');
// Other top-level code goes here.
Cosa cambierà?
Prima di Chrome 68, la richiesta di aggiornamento di /service-worker.js
veniva effettuata tramite la cache HTTP (così come per la maggior parte dei recuperi). Questo significava che se lo script è stato originariamente inviato con Cache-Control:
max-age=600
, gli aggiornamenti entro i successivi 600 secondi (10 minuti) non verrebbero inviati alla rete, quindi l'utente potrebbe non ricevere la versione più aggiornata del service worker. Tuttavia, se il valore di max-age
fosse
superiore a 86.400 (24 ore), viene trattato come se fosse 86.400, per evitare che gli utenti rimangano bloccati
per sempre su una determinata versione.
A partire dalla versione 68, la cache HTTP verrà ignorata quando verranno richiesti aggiornamenti allo script del service worker, quindi le applicazioni web esistenti potrebbero notare un aumento della frequenza delle richieste per lo script del service worker. Le richieste per importScripts
verranno comunque inviate tramite la cache HTTP. Tuttavia, questa è solo l'impostazione predefinita: è disponibile una nuova opzione di registrazione, updateViaCache
, che offre il controllo su questo comportamento.
updateViaCache
Ora gli sviluppatori possono passare una nuova opzione quando chiamano navigator.serviceWorker.register()
: il parametro updateViaCache
.
Può assumere uno dei tre valori seguenti: 'imports'
, 'all'
o 'none'
.
I valori determinano se e come entra in gioco la cache HTTP standard del browser quando si effettua la richiesta HTTP per verificare la presenza di risorse dei service worker aggiornate.
Se il criterio viene impostato su
'imports'
, la cache HTTP non verrà mai consultata durante il controllo della disponibilità di aggiornamenti dello script/service-worker.js
, ma lo sarà durante il recupero di eventuali script importati (nel nostro esempiopath/to/import.js
). Questo è il comportamento predefinito e corrisponde a quello a partire da Chrome 68.Se il criterio viene impostato su
'all'
, la cache HTTP verrà consultata quando si effettuano richieste sia per lo script/service-worker.js
di primo livello, sia per gli eventuali script importati all'interno del worker di servizio, ad esempiopath/to/import.js
. Questa opzione corrisponde al comportamento precedente in Chrome prima della 68.Se il criterio viene impostato su
'none'
, la cache HTTP non verrà consultata quando si effettuano richieste per il/service-worker.js
di primo livello o per eventuali script importati, come l'ipoteticopath/to/import.js
.
Ad esempio, il seguente codice registrerà un service worker e assicura che la cache HTTP non venga mai consultata durante il controllo della disponibilità di aggiornamenti per lo script /service-worker.js
o per eventuali script a cui viene fatto riferimento tramite importScripts()
all'interno di /service-worker.js
:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js', {
updateViaCache: 'none',
// Optionally, set 'scope' here, if needed.
});
}
Verifica la presenza di aggiornamenti degli script importati
Prima di Chrome 78, qualsiasi script del service worker caricato tramite importScripts()
veniva recuperato una sola volta (prima verificandolo con la cache HTTP o tramite la rete, a seconda della configurazione di updateViaCache
). Dopo questo recupero iniziale, i dati vengono archiviati internamente dal browser e non vengono mai recuperati di nuovo.
L'unico modo per forzare un service worker già installato a rilevare le modifiche in uno script importato era modificare l'URL dello script, in genere aggiungendo un valore di servizio (ad es. importScripts('https://example.com/v1.1.0/index.js')
) o includendo un hash dei contenuti (ad es. importScripts('https://example.com/index.abcd1234.js')
). Un effetto collaterale della modifica dell'URL importato è che la modifica dei contenuti dello script del service worker di primo livello attiva la modifica del flusso dei contenuti del worker di servizio di livello superiore, che a sua volta attiva il flusso dei contenuti del worker di servizio di livello superiore.
A partire da Chrome 78, ogni volta che viene eseguito un controllo degli aggiornamenti per un file del Service worker di primo livello, vengono effettuati contemporaneamente dei controlli per determinare se i contenuti degli script importati sono stati modificati. A seconda delle intestazioni Cache-Control
utilizzate, questi controlli degli script importati potrebbero essere eseguiti dalla cache HTTP se updateViaCache
è impostato su 'all'
o 'imports'
(il valore predefinito) oppure i controlli potrebbero essere eseguiti direttamente sulla rete se updateViaCache
è impostato su 'none'
.
Se un controllo degli aggiornamenti per uno script importato comporta una differenza byte per byte rispetto a quanto precedentemente archiviato dal service worker, questo attiverà a sua volta il flusso di aggiornamento completo del service worker, anche se il file del service worker di primo livello rimane lo stesso.
Il comportamento di Chrome 78 corrisponde a quello implementato da Firefox diversi anni fa, con Firefox 56. Questo comportamento viene già implementato in Safari.
Cosa devono fare gli sviluppatori?
Se hai disattivato in modo efficace la memorizzazione nella cache HTTP per lo script /service-worker.js
pubblicandolo
con Cache-Control: max-age=0
(o un valore simile), non dovresti notare alcuna modifica a causa
del nuovo comportamento predefinito.
Se pubblichi il tuo script /service-worker.js
con la memorizzazione nella cache HTTP abilitata, intenzionalmente o perché è solo l'impostazione predefinita per l'ambiente di hosting,
potresti iniziare a vedere un aumento di richieste HTTP aggiuntive per /service-worker.js
effettuate contro
il tuo server: si tratta di richieste che venivano soddisfatte dalla cache HTTP. Se vuoi continuare a consentire al valore dell'intestazione Cache-Control
di influire sull'aggiornamento di /service-worker.js
, devi iniziare a impostare esplicitamente updateViaCache: 'all'
quando registri il tuo service worker.
Dato che le versioni precedenti del browser potrebbero avere più utenti in coda, è comunque una buona idea continuare a impostare l'intestazione HTTP Cache-Control: max-age=0
negli script dei service worker, anche se i browser più recenti potrebbero ignorarli.
Gli sviluppatori possono sfruttare questa opportunità per decidere se disattivare esplicitamente la memorizzazione nella cache HTTP per gli script importati e aggiungere updateViaCache: 'none'
alla registrazione dei service worker, se opportuno.
Pubblicazione di script importati
A partire da Chrome 78, gli sviluppatori potrebbero vedere un numero maggiore di richieste HTTP in entrata per le risorse caricate tramite importScripts()
, poiché ora verranno controllate la presenza di aggiornamenti.
Se vuoi evitare questo traffico HTTP aggiuntivo, imposta intestazioni Cache-Control
di lunga durata durante la pubblicazione di script che includono semver o hash negli URL e affidati al comportamento updateViaCache
predefinito di 'imports'
.
In alternativa, se vuoi che gli script importati vengano controllati frequenti
per verificare la presenza di aggiornamenti
frequenti, assicurati di pubblicarli con Cache-Control: max-age=0
o di utilizzare updateViaCache: 'none'
.
Per approfondire
"The Service Worker Lifecycle" e "Memorizzazione nella cache best practice & max-age gochas", entrambi di Jake Archibald, sono consigliati a tutti gli sviluppatori che eseguono il deployment di qualsiasi cosa sul web.