modulo 07 / lezione 39

Debugging asincrono e interfacce dinamiche

Service Worker, cache aggressiva, source map

Diagnosticare bug provocati da cache di Service Worker o CDN. Collegare codice sorgente, bundle e componente renderizzato attraverso le source map.

55 min Debugging

In parole semplici

Due categorie di bug che sembrano “magia nera”:

  1. Cache aggressiva: hai aggiornato il sito, ma alcuni utenti vedono ancora la vecchia versione. La colpa è di Service Worker, CDN, o cache HTTP.
  2. Stack illeggibile: l’errore in produzione punta a main.abc123.js:1:5432. Il sorgente originale era TypeScript di 2000 righe. La colpa è di source map assenti o non caricate.

Entrambi si curano con strumenti dedicati. Vederli la prima volta è disorientante; la seconda, è routine.

Parole nuove

  • Service Worker (SW): script che intercetta le richieste della pagina.
  • Cache API: storage di richieste/risposte HTTP usato dai SW.
  • CDN cache: cache lato CDN (Cloudflare, Fastly, CloudFront).
  • source map: file .map che collega bundle minificato a sorgenti originali.
  • bundle: file finale prodotto dal builder (Vite, webpack, esbuild).

Cosa impari

  • Riconoscere cache aggressive di Service Worker.
  • Diagnosticare cache HTTP/CDN.
  • Caricare e usare source map in produzione e in DevTools.

Service Worker: come fa “magia”

Un SW si registra una volta e da quel momento intercetta ogni richiesta:

self.addEventListener("fetch", (event) => {
  event.respondWith(
    caches.match(event.request).then(cached => cached || fetch(event.request))
  );
});

Se ha una risposta in cache, la serve senza contattare il server. Veloce, offline-friendly, ma se non c’è strategia di invalidazione, lo stesso bundle viene servito per sempre.

Sintomi di cache di Service Worker

  • Modifichi il sito, ricarichi, vedi vecchia versione.
  • Hard reload (Ctrl+Shift+R) non aiuta su alcune risorse.
  • Network mostra (from ServiceWorker).
  • Utenti diversi vedono versioni diverse.
  • Bug “risolto” che torna su alcune sessioni.

Diagnosi

  1. DevTools → Application → Service Workers.
  2. Vedi i SW registrati per il sito. Stato: activated, redundant, installing.
  3. Spunta Update on reload in dev: ad ogni reload il SW si aggiorna.
  4. Spunta Bypass for network in dev: il SW non risponde, va in rete.

Per cancellare:

  • Click su “Unregister” sul SW.
  • Application → Cache Storage → cancella le entry pertinenti.
  • Ricarica.

Strategie di SW (cenno)

  • Cache First: prima cache, poi rete. Veloce, rischio di obsolescenza.
  • Network First: prima rete, fallback cache. Aggiornato, lento offline.
  • Stale While Revalidate: serve cache immediatamente e aggiorna in background.

Per ogni bug di cache, capisci quale strategia è in uso.

Cache HTTP e CDN

Anche senza SW, ci sono livelli di cache:

  • Browser cache (header Cache-Control, ETag, Last-Modified).
  • CDN cache (Cloudflare, Fastly, CloudFront).
  • Reverse proxy (Nginx, Varnish).

Header utili:

Cache-Control: max-age=3600, public
Cache-Control: no-store
Cache-Control: must-revalidate

Diagnosi:

  • In Network, ogni risposta mostra from disk cache, from memory cache o niente (= rete).
  • Su CDN: header come cf-cache-status (Cloudflare), x-cache (Fastly/CloudFront).

Per forzare bypass durante debug:

  • DevTools → Network → ☑ “Disable cache” (solo con DevTools aperto).
  • Da terminale: curl -H "Cache-Control: no-cache" ....

Source map: cosa, come, perché

In produzione, il codice è minificato:

function calcolaSconto(prezzo,percentuale){if(percentuale==null)return prezzo;return prezzo-(prezzo*percentuale/100)}

Più piccolo, più veloce, illeggibile. Il source map (.map) mappa byte del bundle a riga del sorgente.

Genera source map nel build:

  • Vite/esbuild/webpack: opzione sourcemap: true.

In DevTools, le source map vengono usate automaticamente se trovate. Stack trace mostrano nomi originali.

Caricamento condizionato

Se non vuoi servire source map al pubblico (per non esporre il codice):

  • Caricale solo per utenti autenticati o per IP interni.
  • Caricale via header dal sistema di error monitoring (Sentry).

Per debug, attiva temporaneamente:

//# sourceMappingURL=main.abc123.js.map

(commento alla fine del bundle).

Quando lo stack non si risolve

Se DevTools non risolve i nomi:

  1. Verifica che il file .map sia stato deployato.
  2. Apri il bundle in Sources → “Add source map”.
  3. Inserisci URL o carica file locale.
  4. Verifica che la mappatura sia plausibile.

Strumenti standalone: source-map-explorer, webpack-bundle-analyzer.

Esempio risolto: errore “minificato” che diventa leggibile

Senza source map:

TypeError: Cannot read properties of null (reading 'name')
    at e (main.abc123.js:1:5432)
    at t.handleClick (main.abc123.js:1:7891)

Con source map caricata:

TypeError: Cannot read properties of null (reading 'name')
    at mostraUtente (src/components/UserCard.tsx:42:18)
    at HTMLButtonElement.handleClick (src/components/UserCard.tsx:60:5)

Lettura immediata: UserCard.tsx, riga 42. Indagine pronta.

Esercizio guidato

  1. Apri un sito reale che usi un SW (PWA come twitter.com mobile, gmail).
  2. Application → Service Workers. Quali strategie vedi?
  3. Cache Storage: ispeziona quale entry contiene.
  4. Per un tuo progetto, abilita sourcemap: true in Vite. Builda. Apri il sito buildato in DevTools e provoca un errore. Vedi sorgente o bundle?
  5. Disattiva il .map (rimuovi commento o file). Provoca lo stesso errore. Confronta.

Errori frequenti del principiante

  • Demonizzare il SW. È utile. Va gestito.
  • Saltare “Update on reload” in dev. Si combatte contro la propria cache per settimane.
  • Deployare senza source map. Errori in produzione restano illeggibili.
  • Deployare source map pubbliche con commenti che svelano segreti. Verifica cosa contiene il .map.