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. Tuttavia, gli standard per la memorizzazione nella cache sul web risalgono al 1999 e sono definiti in modo piuttosto ampio. Determinare se un file, come un CSS o un'immagine, debba essere recuperato di nuovo dalla rete o caricato dalla cache è una scienza un po' imprecisa.

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 gli utenti dispongano della versione più aggiornata disponibile: se hai apportato delle modifiche, le modifiche dovrebbero riflettersi 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. In alternativa, hai creato un service worker che pubblicherà un sito completamente offline prima di verificare se è aggiornato. Si tratta di un'opzione estrema, valida e utilizzata per molte esperienze web simili ad app offline, ma il web non deve essere necessariamente basato solo sulla cache o solo sulla rete.

Sfondo

In qualità di sviluppatori web, siamo tutti abituati all'idea di avere una "cache non aggiornata". Sappiamo però, quasi istintivamente, quali sono gli strumenti disponibili per risolvere questo 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.

Questa era un'idea ben intenzionale in un certo tempo, ma data la natura strettamente integrata dei siti web di oggi, questo comportamento predefinito significa che è possibile ottenere uno stato in cui un utente ha file progettati per versioni diverse del tuo sito web (ad es. il codice JS della release di martedì e il CSS della release di venerdì), il tutto perché quei 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, si reca sulla rete per verificare 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").

Questo processo di convalida è relativamente economico in termini di byte trasferiti: se un file immagine di grandi dimensioni non è cambiato, il browser riceverà una piccola risposta 304, ma ha una latenza, in quanto l'utente deve comunque accedere alla rete per scoprirlo. Ed è questo il principale svantaggio 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"
    }
  }
]

Sebbene continui a consigliarla come impostazione predefinita sensata, non è altro che questo: l'impostazione predefinita. Continua a leggere per scoprire come eseguire l'upgrade delle impostazioni predefinite.

URL con impronta digitale

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 di questi file, puoi chiedere in tutta sicurezza ai browser degli utenti finali di memorizzarli nella cache per molto tempo configurandoli con questo intestazione:

Cache-Control: max-age=31536000,immutable

Questo valore è un anno in secondi. E, in base alla specifica, è effettivamente uguale a "per sempre".

È importante non generare questi hash manualmente, perché è un lavoro troppo manuale. Per farlo, puoi utilizzare strumenti come Webpack, Rollup e così via. Per saperne di più, consulta il report sugli strumenti.

Ricorda che non è solo JavaScript che può trarre vantaggio dagli URL con fingerprint; 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 con ogni release.

Ovviamente, non possiamo rinominare in questo modo le nostre pagine "amichevoli" rivolte agli utenti: rinominare il file index.html in index.abcd12.html non è fattibile, non puoi chiedere agli utenti di visitare un nuovo URL ogni volta che caricano il tuo sito. Questi URL semplici non possono essere rinominati e memorizzati nella cache in questo modo, il che porta a una possibile via di mezzo.

La via di mezzo

Ovviamente, esiste una via di mezzo per la memorizzazione nella cache. Ho presentato due opzioni estreme: cache mai o cache sempre. Ci saranno anche una serie di file che potresti voler memorizzare nella cache per un certo periodo, come gli URL "dedicati" che ho menzionato sopra.

Se invece vuoi memorizzare nella cache questi URL "semplificati" e il relativo codice HTML, vale la pena considerare quali dipendenze includono, in che modo potrebbero essere memorizzati nella cache e in che modo la memorizzazione degli URL per un determinato periodo di tempo potrebbe interessarti. 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 parla di questo tipo di impostazione: vuoi memorizzare nella cache per un'ora, per diverse ore e così via. Per impostare questo tipo di cache, utilizza un'intestazione come questa (che memorizza nella cache per 3600 secondi, ovvero 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 il CSS, in quanto causa modifiche al modo in cui viene visualizzato il codice HTML.
  • 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 avere limitazioni di frequenza, quindi memorizza nella cache un'immagine dello stato di build 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 e hai a disposizione una serie di opzioni per assicurarti che il browser esegua solo le operazioni necessarie 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 Impedire le richieste di rete non necessarie con la cache HTTP.