Rimozione dei service worker che presentano errori

A volte viene implementato un service worker con bug, ma si verificano dei problemi. Ad esempio, è possibile analizzare un service worker al momento della registrazione e completare l'installazione. Tuttavia, un evento con bug in un evento fetch potrebbe causare la mancata risposta alle richieste, restituendo una pagina vuota. Un'altra possibilità è che il markup della pagina venga memorizzato in modo aggressivo nella cache e che un service worker restituisca solo risposte a markup obsolete da un'istanza Cache per le visite successive.

I Service worker possono andare contro corrente in vari modi e questo è un problema terrificante che deve trovarsi in un sito web di produzione. Anche così, non tutto è perduto. Esistono dei modi per risolvere la situazione e tornare in pista.

Deployment di un service worker autonomo

Per gestire un service worker che presenta bug è sufficiente eseguire il deployment di un service worker no-op di base che si installa e si attiva immediatamente senza un gestore di eventi fetch:

// sw.js

self.addEventListener('install', () => {
  // Skip over the "waiting" lifecycle state, to ensure that our
  // new service worker is activated immediately, even if there's
  // another tab open controlled by our older service worker code.
  self.skipWaiting();
});

self.addEventListener('activate', () => {
  // Optional: Get a list of all the current open windows/tabs under
  // our service worker's control, and force them to reload.
  // This can "unbreak" any open windows/tabs as soon as the new
  // service worker activates, rather than users having to manually reload.
  self.clients.matchAll({
    type: 'window'
  }).then(windowClients => {
    windowClients.forEach((windowClient) => {
      windowClient.navigate(windowClient.url);
    });
  });
});

Questo service worker verrà installato e attivato immediatamente chiamando self.skipWaiting() nell'evento install. Facoltativamente, nell'evento activate può essere eseguito il deployment di codice aggiuntivo per ricaricare forzatamente qualsiasi altra scheda aperta con un WindowClient controllato dal service worker.

È molto importante che un service worker autonomo non contenga un gestore di eventi fetch. Quando un service worker non gestisce le richieste, queste vengono trasmesse al browser come se non fosse presente alcun service worker. Dopo il deployment di un service worker autonomo, questo può essere corretto e implementato come aggiornamento in un secondo momento.

Questo approccio funziona in parte perché i browser offrono solide misure di protezione contro il posizionamento dei service worker nella cache HTTP e perché eseguono controlli byte per byte dei contenuti dei service worker per verificare la presenza di aggiornamenti. Queste impostazioni predefinite consentono di eseguire il deployment di una sostituzione autonoma di un service worker che presenta bug per risolvere rapidamente il problema.

Misure aggiuntive da adottare

Il deployment di un service worker autonomo dovrebbe essere sufficiente per neutralizzare un service con bug, ma se necessario possono essere adottate misure aggiuntive.

E se non conosci l'URL del service worker precedente?

A volte l'URL di un service worker installato in precedenza è sconosciuto. Ciò potrebbe essere dovuto al fatto che il file è sottoposto al controllo delle versioni (ad esempio, il nome del file contiene un hash). In questo caso può essere difficile eseguire il deployment di un service worker no-op che corrisponda all'URL di ogni service worker precedente che potrebbe essere registrato. Questo è in contrasto con le best practice, poiché gli sviluppatori probabilmente non ricorderanno tutti gli hash per ogni versione del service worker di cui è stato eseguito il deployment.

Fortunatamente, viene inviata un'utile intestazione della richiesta HTTP con la richiesta di uno script del service worker: Service-Worker. Sul server web, controlla la presenza di questa intestazione e intercetta la richiesta di fornire invece un service worker no-op. Il completamento di questa operazione dipende dal server web e dallo stack di backend utilizzati, quindi consulta la documentazione del linguaggio pertinente per informazioni su come fare.

Per quanto riguarda i deployment dei service worker futuri, continua a utilizzare i nomi degli asset senza versione (ad esempio sw.js). In questo modo le cose saranno molto meno complicate in seguito.

Imposta un'intestazione Clear-Site-Data

Alcuni browser annullano la registrazione di tutti i service worker per un'origine se è impostata un'intestazione della risposta Clear-Site-Data con il valore 'storage'. Tuttavia, con questo approccio occorre essere consapevoli di alcuni aspetti:

  • Tieni presente che questa operazione cancellerà tutto lo spazio di archiviazione per l'origine associata. Sono inclusi localStorage, IndexedDB, sessionStorage e altro spazio di archiviazione (ma non la cache HTTP per l'origine).
  • Questa intestazione non è supportata in tutti i browser.

Poiché il supporto per questa intestazione non è completo, non è possibile fare affidamento su questa intestazione per risolvere il problema. È quindi preferibile considerare Clear-Site-Data come misura da adottare in aggiunta al deployment di un service worker autonomo.

Il danno non è permanente

Può essere spaventoso quando l'esperienza utente viene interrotta da un service worker che presenta bug, in particolare per i siti web più grandi e noti, ma il danno è temporaneo e reversibile.

Se è necessario eseguire il deployment di un service worker autonomo per risolvere la situazione, prenditi del tempo dopo l'evento per capire esattamente cosa non ha funzionato. In futuro, assicurati che un service worker gestisca solo le richieste previste. Esegui spesso test nella gestione temporanea e implementa gli aggiornamenti solo in caso di sicurezza.