Me encanta tu caché ❤️

Los usuarios que carguen tu sitio por segunda vez utilizarán su caché HTTP, así que asegúrate de que funcione correctamente.

Esta publicación complementa el video Love your cache, que forma parte del contenido extendido en la Chrome Dev Summit 2020. Asegúrate de mirar el siguiente video:

Cuando los usuarios cargan tu sitio por segunda vez, el navegador utilizará recursos dentro de la caché HTTP para acelerar la carga. Sin embargo, los estándares para el almacenamiento en caché en la Web se remontan a 1999 y se definen de forma bastante amplia; determinar si un archivo, como CSS o una imagen, se puede recuperar de la red o cargarse desde la caché es una ciencia inexacta.

En esta entrada, abordaremos una configuración predeterminada razonable y moderna para el almacenamiento en caché, que en realidad no hace almacenamiento en caché. Pero ese es solo el valor predeterminado y, por supuesto, tiene más matices que solo "desactivarlo". Sigue leyendo para conocer todos los detalles.

Objetivos

Cuando se carga un sitio por segunda vez, tienes dos objetivos:

  1. Asegúrate de que los usuarios obtengan la versión más actualizada disponible. Si hiciste cambios, debería reflejarse rápidamente.
  2. Realiza la acción 1 mientras recuperas lo menos posible de la red

En el sentido más amplio, solo querrás enviar el cambio más pequeño a tus clientes cuando vuelvan a cargar tu sitio. Además, estructurar el sitio para garantizar la distribución más eficiente de cualquier cambio es un desafío (obtén más información a continuación y en el video).

Dicho esto, también tienes otros controles a la hora de considerar el almacenamiento en caché. Tal vez hayas decidido permitir que la caché HTTP del navegador de un usuario conserve tu sitio durante mucho tiempo, de manera que no se necesiten solicitudes de red para entregarla. O construyeste un service worker que entregará un sitio por completo sin conexión antes de verificar si está actualizado. Esta es una opción extrema válida, y se usa para muchas experiencias web similares a las apps que priorizan el uso sin conexión, pero la Web no necesita estar en un extremo de solo caché ni en uno completamente solo de red.

Información general

Como desarrolladores web, estamos acostumbrados a la idea de tener una "caché inactiva". Sin embargo, conocemos, casi por instinto, las herramientas disponibles para resolver esto: haz una "actualización forzada", abre una ventana de incógnito o usa alguna combinación de las herramientas para desarrolladores de tu navegador para borrar los datos de un sitio.

Los usuarios normales que acceden a Internet no tienen el mismo lujo. Por lo tanto, si bien tenemos algunos objetivos principales para garantizar que nuestros usuarios la pasen bien con su segunda carga, también es importante asegurarse de que no tengan un malo momento o no se detengan. (Mira el video si quieres que hablemos sobre cómo casi que se bloqueaba el sitio web.dev/live).

A modo de referencia, una razón muy común para la "caché inactiva" es, en realidad, la configuración predeterminada de la época de 1999 para el almacenamiento en caché. Se basa en el encabezado Last-Modified:

Diagrama que muestra por cuánto tiempo el navegador de un usuario almacena en caché diferentes elementos
Los recursos generados en diferentes momentos (en gris) se almacenarán en caché durante distintos momentos, por lo que una 2a carga puede obtener una combinación de recursos actualizados y almacenados en caché

Cada archivo que cargas se conserva por un 10% adicional de su vida útil actual, como lo ve tu navegador. Por ejemplo, si se creó index.html hace un mes, tu navegador almacenará en caché durante otros tres días.

En aquel momento, esta era una idea bien intencional, pero dada la naturaleza estrechamente integrada de los sitios web actuales, este comportamiento predeterminado significa que es posible llegar a un estado en el que un usuario tiene archivos diseñados para diferentes versiones de tu sitio web (p.ej., el JS de la versión del martes y el CSS de la versión del viernes), todo porque esos archivos no se actualizaron exactamente al mismo tiempo.

El camino bien iluminado

Una opción predeterminada moderna para el almacenamiento en caché es no almacenar en caché en absoluto y usar CDN para acercar el contenido a tus usuarios. Cada vez que un usuario carga tu sitio, irá a la red para ver si está actualizado. Esta solicitud tendrá una latencia baja, ya que la proporcionará una CDN ubicada geográficamente cerca de cada usuario final.

Puedes configurar tu host web para que responda a las solicitudes web con este encabezado:

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

En esencia, esto indica que el archivo es válido por ningún tiempo y debes validarlo desde la red antes de poder usarlo de nuevo (de lo contrario, solo es "sugerido").

Este proceso de validación es relativamente económico en términos de bytes transferidos. Si un archivo de imagen grande no cambió, tu navegador recibirá una respuesta 304 pequeña, pero cuesta latencia, ya que el usuario debe ir a la red para averiguarlo. Esta es la desventaja principal de este enfoque. Puede funcionar muy bien para las personas que tienen conexiones rápidas en primer lugar y donde la CDN elegida tiene una gran cobertura, pero no para aquellas personas que tienen conexiones móviles más lentas o usan una infraestructura deficiente.

En cualquier caso, este es un enfoque moderno que es el predeterminado en una CDN popular, Netlify, pero se puede configurar en casi cualquier CDN. En Firebase Hosting, puedes incluir este encabezado en la sección de hosting del archivo 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"
    }
  }
]

Así que, si bien sugiero que esto sea un valor predeterminado razonable, es solo eso: es el valor predeterminado. Sigue leyendo para descubrir cómo intervenir y actualizar los valores predeterminados.

URLs con huella digital

Si incluyes un hash del contenido del archivo en el nombre de los elementos, las imágenes y otros elementos que se entregan en tu sitio, puedes asegurarte de que estos archivos siempre tendrán contenido único. Esto generará archivos llamados sitecode.af12de.js, por ejemplo. Cuando tu servidor responda a las solicitudes de estos archivos, puedes indicar de manera segura a los navegadores del usuario final que los almacenen en caché durante mucho tiempo mediante la configuración con este encabezado:

Cache-Control: max-age=31536000,immutable

Este valor es un año, en segundos. Según la especificación, esto es efectivamente igual a "forever".

Es importante destacar que no debes generar estos hash de forma manual, ya que es demasiado trabajo manual. Puedes usar herramientas como Webpack, Rollup y otras más para ayudarte con esto. Asegúrate de obtener más información al respecto en el Informe de herramientas.

Recuerda que las URLs con huellas digitales no son solo JavaScript; los elementos como los íconos, los CSS y otros archivos de datos inmutables también pueden tener este nombre. Además, asegúrate de mirar el video anterior para obtener más información sobre la división de código, que te permite enviar menos código cada vez que tu sitio cambia.

Independientemente de la manera en que tu sitio se acerque al almacenamiento en caché, este tipo de archivos con huellas digitales son increíblemente valiosos para cualquier sitio que compiles. La mayoría de los sitios no cambian en cada versión.

Por supuesto, no podemos cambiar el nombre de nuestras páginas 'adaptables' para los usuarios de esta forma: cambiar el nombre de tu archivo index.html a index.abcd12.html; eso es inviable y no puedes indicarles a los usuarios que vayan a una URL nueva cada vez que cargan tu sitio. No se puede cambiar el nombre de estas URLs "compatibles" ni almacenarlas en caché de esta manera, lo que me lleva a un posible punto intermedio.

El término medio

Evidentemente, hay espacio para un punto intermedio cuando se trata del almacenamiento en caché. Presenté dos opciones extremas: caché nunca o caché siempre. Además, habrá varios archivos que quizás quieras almacenar en caché por un tiempo, como las URLs "compatibles" que mencioné anteriormente.

Si quieres almacenar en caché estas URLs "optimizadas" y su código HTML, te recomendamos que consideres qué dependencias incluyen, cómo se pueden almacenar en caché y cómo te podría afectar almacenar sus URLs durante un período determinado. Veamos una página HTML que incluye una imagen como esta:

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

Si actualizas o cambias tu sitio borrando o cambiando esta imagen de carga diferida, es posible que los usuarios que vean una versión almacenada en caché de tu código HTML vean una imagen incorrecta o faltante, ya que todavía almacenan en caché el /images/foo.jpeg original cuando vuelven a visitar tu sitio.

Si tienes cuidado, es posible que esto no te afecte. Pero, en términos generales, es importante recordar que tu sitio, cuando los usuarios finales lo almacenan en caché, ya no existe solo en tus servidores. En cambio, puede existir en piezas dentro de las memorias caché de los navegadores del usuario final.

En general, la mayoría de las guías sobre almacenamiento en caché hablarán sobre este tipo de configuración: ¿deseas almacenar en caché durante una hora, varias horas, etc.? Para configurar este tipo de caché, usa un encabezado como este (que se almacena en caché durante 3, 600 segundos o una hora):

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

Un último punto. Si creas contenido oportuno al que los usuarios suelen acceder solo una vez, como los artículos de noticias, mi opinión es que nunca se deben almacenar en caché y que debes usar el valor predeterminado razonable anterior. Creo que, a menudo, sobreestimamos el valor del almacenamiento en caché sobre el deseo de los usuarios de ver siempre el mejor contenido y más reciente, como una actualización crítica sobre una noticia o un evento actual.

Opciones que no son HTML

Además de HTML, algunas otras opciones para los archivos que se encuentran en el medio incluyen las siguientes:

  • En general, busca recursos que no afecten a otros

    • Por ejemplo: Evita usar CSS, ya que provoca cambios en la forma en que se renderiza tu código HTML.
  • Imágenes grandes que se usan como parte de artículos oportunos

    • Es probable que los usuarios no visiten ningún artículo más de un par de veces, así que no almacenes fotos ni imágenes hero para siempre ni desperdicies almacenamiento.
  • Elemento que representa un elemento que tiene vida útil

    • Es posible que los datos JSON sobre el clima solo se publiquen cada hora, por lo que puedes almacenar en caché el resultado anterior durante una hora; no cambiará en tu ventana
    • Las compilaciones de un proyecto de código abierto pueden tener un límite de frecuencia, por lo que debes almacenar en caché una imagen de estado de compilación hasta que sea posible que el estado cambie.

Resumen

Cuando los usuarios cargan tu sitio por segunda vez, ya obtuviste un voto de confianza, es decir, quieren volver y obtener más de lo que ofreces. En este punto, no siempre se trata de reducir el tiempo de carga, y tienes varias opciones disponibles para asegurarte de que el navegador haga solo el trabajo necesario para brindar una experiencia rápida y actualizada.

El almacenamiento en caché no es un concepto nuevo en la Web, pero tal vez necesite un valor predeterminado razonable. Considera usar uno y habilitar mejores estrategias de almacenamiento en caché cuando las necesites. ¡Gracias por leer esta información!

Consulta también

Para obtener una guía general sobre la caché HTTP, consulta Evita solicitudes de red innecesarias con la caché HTTP.