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.
In parole semplici
Due categorie di bug che sembrano “magia nera”:
- Cache aggressiva: hai aggiornato il sito, ma alcuni utenti vedono ancora la vecchia versione. La colpa è di Service Worker, CDN, o cache HTTP.
- 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
.mapche 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
- DevTools → Application → Service Workers.
- Vedi i SW registrati per il sito. Stato: activated, redundant, installing.
- Spunta Update on reload in dev: ad ogni reload il SW si aggiorna.
- 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 cacheo 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:
- Verifica che il file
.mapsia stato deployato. - Apri il bundle in Sources → “Add source map”.
- Inserisci URL o carica file locale.
- 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
- Apri un sito reale che usi un SW (PWA come twitter.com mobile, gmail).
- Application → Service Workers. Quali strategie vedi?
- Cache Storage: ispeziona quale entry contiene.
- Per un tuo progetto, abilita
sourcemap: truein Vite. Builda. Apri il sito buildato in DevTools e provoca un errore. Vedi sorgente o bundle? - 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.