La tua cache ❤️

Gli utenti che caricano il tuo sito una seconda volta utilizzeranno la cache HTTP, quindi assicurati che funzioni correttamente.

Questo post è correlato al video Ama la tua cache, che fa parte dei contenuti aggiuntivi del Chrome Dev Summit 2020. Guarda il video:

Quando gli utenti caricano il sito una seconda volta, il browser utilizza le risorse all'interno della cache HTTP per velocizzare il caricamento. Ma gli standard per la memorizzazione nella cache sul web risalgono al 1999 e sono definiti in modo abbastanza ampio: determinare se un file, come CSS o un'immagine, potrebbe essere recuperato di nuovo dalla rete anziché essere caricato dalla cache è un po' una scienza inesatta.

In questo post, illustrerò un'impostazione predefinita moderna e sensata per la memorizzazione nella cache, che non esegue alcuna memorizzazione nella cache. Tuttavia, si tratta solo del valore predefinito e, ovviamente, è più sfumato di una semplice "disattivazione". Continua a leggere.

Obiettivi

Quando un sito viene caricato per la seconda volta, hai due obiettivi:

  1. Assicurati che i tuoi utenti ricevano la versione più aggiornata disponibile. Se hai apportato una modifica, questa dovrebbe essere applicata rapidamente
  2. Esegui il passaggio 1 recuperando il meno possibile dalla rete

In senso più ampio, vuoi inviare ai clienti solo la minima modifica quando caricano di nuovo il tuo sito. Inoltre, strutturare il sito in modo da garantire la distribuzione più efficiente di qualsiasi modifica è una sfida (di seguito e nel video sono riportate maggiori informazioni in merito).

Detto ciò, esistono anche altre manopole quando si considera la memorizzazione nella cache: forse hai deciso di lasciare che la cache HTTP del browser di un utente trattiene il tuo sito per un lungo periodo in modo che non siano necessarie richieste di rete per la sua pubblicazione. Oppure hai costruito un service worker che pubblicherà un sito interamente offline prima di controllare se è aggiornato. Si tratta di un'opzione estrema, valida e utilizzata per molte esperienze web simili a quelle di un'app offline, ma non è necessario che il web si trovi in uno stato estremo di solo cache o addirittura di una sola rete.

Sfondo

In qualità di sviluppatori web, siamo tutti abituati all'idea di avere una "cache non aggiornata". Tuttavia, sappiamo, quasi istintivamente, quali sono gli strumenti a nostra disposizione per risolvere il problema: eseguire un "aggiornamento forzato", aprire una finestra di navigazione in incognito o utilizzare una combinazione di strumenti per sviluppatori del browser per cancellare i dati di un sito.

Gli utenti normali su internet non hanno lo stesso lusso. Pertanto, anche se abbiamo alcuni obiettivi principali per garantire che i nostri utenti si divertano con il secondo caricamento, è anche molto importante assicurarsi che non abbiano una esperienza negativa o che non si blocchino. (Guarda il video se vuoi ascoltare la mia storia su come abbiamo rischiato di bloccare il sito web.dev/live.)

Per un po' di contesto, un motivo molto comune per la "cache non aggiornata" è in realtà la modalità predefinita per la memorizzazione nella cache del 1999. Si basa sull'intestazione Last-Modified:

Diagramma che mostra per quanto tempo le diverse risorse vengono memorizzate nella cache dal browser di un utente
Gli asset generati in momenti diversi (in grigio) verranno memorizzati nella cache per periodi diversi, pertanto un secondo caricamento può ottenere una combinazione di asset memorizzati nella cache e nuovi

Ogni file caricato viene conservato per un ulteriore 10% della sua durata attuale, come lo vede il browser. Ad esempio, se index.html è stato creato un mese fa, viene memorizzato nella cache dal browser per altri tre giorni circa.

In passato era un'idea ben intenzionata, ma data la natura strettamente integrata dei siti web di oggi, questo comportamento predefinito significa che è possibile arrivare a uno stato in cui un utente ha file progettati per release diverse del tuo sito web (ad es. il codice JS della release di martedì e il codice CSS della release di venerdì), il tutto perché questi file non sono stati aggiornati esattamente nello stesso momento.

Il percorso ben illuminato

Un'impostazione predefinita moderna per la memorizzazione nella cache è quella di non eseguire alcuna memorizzazione nella cache e di utilizzare le CDN per avvicinare il contenuto agli utenti. Ogni volta che un utente carica il tuo sito, accederà alla rete per vedere se è aggiornato. Questa richiesta avrà una latenza ridotta, in quanto verrà fornita da una CDN geograficamente vicina a ogni utente finale.

Puoi configurare il tuo host web in modo che risponda alle richieste web con questa intestazione:

Cache-Control: max-age=0,must-revalidate,public

In pratica, il file non è valido per nessun periodo di tempo e devi convalidarlo dalla rete prima di poterlo utilizzare di nuovo (altrimenti è solo "suggerito").

Questa procedura di convalida è relativamente economica in termini di byte trasferiti: se un file immagine di grandi dimensioni non è cambiato, il browser riceverà una piccola risposta 304, ma comporta un costo in termini di latenza, poiché l'utente deve comunque accedere alla rete per scoprirlo. E questo è lo svantaggio principale di questo approccio. Può funzionare molto bene per gli utenti con connessioni rapide nei paesi sviluppati e dove la CDN scelta ha una copertura eccezionale, ma non per gli utenti con connessioni mobile più lente o che utilizzano infrastrutture scadenti.

Tuttavia, si tratta di un approccio moderno che è predefinito su una popolare CDN, Netlify, ma può essere configurato su quasi tutte le CDN. Per Firebase Hosting, puoi includere questo intestazione nella sezione di hosting del file firebase.json:

"headers": [
  // Be sure to put this last, to not override other headers
  {
    "source": "**",
    "headers": [ {
      "key": "Cache-Control",
      "value": "max-age=0,must-revalidate,public"
    }
  }
]

Quindi, anche se suggerisco comunque questa soluzione come valida predefinita, è solo quella predefinita. Continua a leggere per scoprire come intervenire e aggiornare i valori predefiniti.

URL con fingerprint

Se includi un hash dei contenuti del file nel nome di asset, immagini e così via pubblicati sul tuo sito, puoi assicurarti che questi file abbiano sempre contenuti unici. Ad esempio, i file avranno il nome sitecode.af12de.js. Quando il tuo server risponde alle richieste relative a questi file, puoi indicare in sicurezza ai browser dell'utente finale di memorizzarli nella cache per un lungo periodo di tempo configurandoli con questa intestazione:

Cache-Control: max-age=31536000,immutable

Questo valore è un anno, in secondi. Secondo le specifiche, questo valore è di fatto uguale a "per sempre".

È importante non generare questi hash manualmente, perché è un lavoro troppo manuale. Puoi utilizzare strumenti come Webpack, Rollup e così via per aiutarti. Assicurati di leggere di più nel report sugli strumenti.

Ricorda che non è solo JavaScript a poter trarre vantaggio dagli URL con impronta; anche asset come icone, CSS e altri file di dati immutabili possono essere denominati in questo modo. Inoltre, guarda il video qui sopra per scoprire di più sulla suddivisione del codice, che ti consente di pubblicare meno codice ogni volta che il tuo sito cambia.

Indipendentemente dall'approccio del tuo sito alla memorizzazione nella cache, questi tipi di file con impronte digitali sono incredibilmente importanti per qualsiasi sito che potresti creare. La maggior parte dei siti non cambia a ogni release.

Ovviamente non possiamo rinominare le nostre pagine "facili" rivolte agli utenti in questo modo: puoi rinominare il tuo file index.html in index.abcd12.html: questa operazione non è fattibile, poiché non puoi chiedere agli utenti di accedere a un nuovo URL ogni volta che caricano il tuo sito. Questi URL "amichevoli" non possono essere rinominati e memorizzati nella cache in questo modo, il che mi fa pensare a un possibile compromesso.

La via di mezzo

Ovviamente c'è spazio per una via di mezzo quando si tratta di memorizzazione nella cache. Ho presentato due opzioni estreme: cache mai o cache sempre. Inoltre, potresti voler memorizzare nella cache per un po' di tempo una serie di file, ad esempio gli URL "amichevoli" che ho menzionato sopra.

Se vuoi memorizzare nella cache questi URL "amichevoli" e il relativo codice HTML, vale la pena di considerare le dipendenze che includono, come possono essere memorizzati nella cache e in che modo la memorizzazione nella cache dei relativi URL per un determinato periodo di tempo potrebbe influire su di te. Esamineremo una pagina HTML che include un'immagine come questa:

<img src="/images/foo.jpeg" loading="lazy" />

Se aggiorni o modifichi il tuo sito eliminando o modificando questa immagine con caricamento differito, gli utenti che visualizzano una versione memorizzata nella cache del tuo codice HTML potrebbero visualizzare un'immagine errata o mancante, perché hanno ancora memorizzato nella cache l'/images/foo.jpeg originale quando visitano di nuovo il tuo sito.

Se fai attenzione, questo potrebbe non riguardarti. In generale, però, è importante ricordare che il tuo sito, quando viene memorizzato nella cache dagli utenti finali, non esiste più solo sui tuoi server. Potrebbe invece essere presente in pezzi all'interno delle cache dei browser degli utenti finali.

In generale, la maggior parte delle guide sulla memorizzazione nella cache parlerà di questo tipo di impostazione: vuoi memorizzare nella cache per un'ora, diverse ore e così via. Per impostare questo tipo di cache, utilizza un'intestazione come questa (che memorizza nella cache per 3600 secondi o un'ora):

Cache-Control: max-age=3600,immutable,public

Un ultimo punto. Se crei contenuti tempestivi che in genere potrebbero essere acceduti dagli utenti solo una volta, come gli articoli di notizie, secondo me non dovrebbero mai essere memorizzati nella cache e dovresti utilizzare il valore predefinito ragionevole riportato sopra. Penso che spesso overestimate il valore della memorizzazione nella cache rispetto al desiderio di un utente di vedere sempre i contenuti più recenti e migliori, ad esempio un aggiornamento critico su una notizia o un evento di attualità.

Opzioni non HTML

Oltre all'HTML, alcune altre opzioni per i file che si trovano a metà tra i due estremi includono:

  • In generale, cerca asset che non influiscono su altri

    • Ad esempio: evita CSS, perché provoca modifiche nel modo in cui il codice HTML viene visualizzato.
  • Immagini di grandi dimensioni utilizzate all'interno di articoli tempestivi

    • I tuoi utenti probabilmente non visiteranno un singolo articolo più di un paio di volte, quindi non memorizzare nella cache foto o immagini hero per sempre e sprecare spazio di archiviazione
  • Una risorsa che rappresenta qualcosa che ha una durata

    • I dati JSON relativi al meteo potrebbero essere pubblicati solo ogni ora, quindi puoi memorizzare nella cache il risultato precedente per un'ora, poiché non cambierà nella finestra
    • Le build di un progetto open source potrebbero essere limitate in termini di frequenza, quindi memorizza nella cache un'immagine dello stato di compilazione finché non è possibile che lo stato cambi

Riepilogo

Quando gli utenti caricano il tuo sito una seconda volta, hanno già dato un voto di fiducia: vogliono tornare e usufruire di più di ciò che offri. A questo punto, non si tratta sempre solo di ridurre il tempo di caricamento, ma hai a disposizione una serie di opzioni per garantire che il browser faccia solo il lavoro necessario per offrire un'esperienza rapida e aggiornata.

La memorizzazione nella cache non è un concetto nuovo sul web, ma forse ha bisogno di un valore predefinito sensato. Valuta la possibilità di utilizzarne uno e di attivare vivamente strategie di memorizzazione nella cache migliori quando ne hai bisogno. Grazie per l'attenzione.

Vedi anche

Per una guida generale sulla cache HTTP, consulta Prevenire richieste di rete non necessarie con la cache HTTP.