Me encanta tu caché ❤️

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

Esta publicación es complementaria del video Ama tu caché, parte del contenido extendido de la Cumbre de desarrolladores de Chrome 2020. Asegúrate de mirar el video:

Cuando los usuarios carguen tu sitio por segunda vez, su navegador usará recursos dentro de su caché HTTP para ayudar a que esa carga sea más rápida. Sin embargo, los estándares de almacenamiento en caché en la Web datan de 1999 y se definen de forma bastante amplia. Determinar si un archivo, como CSS o una imagen, se puede recuperar nuevamente de la red en lugar de cargarse desde la caché es una ciencia un poco inexacta.

En esta publicación, hablaré sobre una configuración predeterminada moderna y sensata para la caché, que en realidad no usa la caché en absoluto. Pero esa es solo la configuración predeterminada y, por supuesto, es más matizada que simplemente “desactivarla”. Sigue leyendo para conocer todos los detalles.

Objetivos

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

  1. Asegúrate de que tus usuarios obtengan la versión más actualizada disponible. Si cambiaste algo, debería reflejarse rápidamente.
  2. Realiza el paso 1 mientras recuperas la menor cantidad posible de la red.

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

Dicho esto, también tienes otros parámetros de control cuando consideras la caché. Quizás decidas permitir que la caché HTTP del navegador de un usuario retenga tu sitio durante mucho tiempo para que no se requieran solicitudes de red para entregarlo. O bien compilaste un service worker que publicará un sitio completamente sin conexión antes de verificar si está actualizado. Esta es una opción extrema, que es válida y se usa para muchas experiencias web similares a apps que priorizan la conexión sin conexión, pero la Web no tiene que estar en un extremo de solo caché o incluso en un extremo de solo red.

Segundo plano

Como desarrolladores web, todos estamos acostumbrados a la idea de tener una "caché inactiva". Sin embargo, sabemos, casi de forma instintiva, las herramientas disponibles para resolver este problema: hacer una "actualización forzada", abrir una ventana de incógnito o usar alguna combinación de las herramientas para desarrolladores de tu navegador para borrar los datos de un sitio.

Los usuarios comunes de Internet no tienen ese lujo. Por lo tanto, si bien tenemos algunos objetivos principales para garantizar que nuestros usuarios disfruten de la 2ª carga, también es muy importante asegurarnos de que no tengan una mala experiencia o se bloqueen. (mira el video si quieres escucharme hablar sobre cómo casi bloqueamos el sitio web.dev/live).

A modo de referencia, un motivo muy común de la "caché inactiva" es, en realidad, la configuración predeterminada de la caché de la era de 1999. Se basa en el encabezado Last-Modified:

Diagrama que muestra durante cuánto tiempo el navegador de un usuario almacena en caché los diferentes recursos
Los recursos generados en diferentes momentos (en gris) se almacenarán en caché durante diferentes períodos, de modo que una 2ª carga pueda obtener una combinación de recursos almacenados en caché y nuevos.

Cada archivo que cargues se conservará durante un 10% adicional de su vida útil actual, según lo vea tu navegador. Por ejemplo, si index.html se creó hace un mes, el navegador lo almacenará en caché durante otros tres días.

Esta era una idea bien intencionada en su momento, pero, debido a la naturaleza de integración estrecha de los sitios web actuales, este comportamiento predeterminado significa que es posible llegar a un estado en el que un usuario tenga 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.

La ruta bien iluminada

Una configuración predeterminada moderna para el almacenamiento en caché es no almacenar en caché en absoluto y usar CDN para acercar tu contenido a los usuarios. Cada vez que un usuario cargue 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

Esto básicamente indica que el archivo no es válido en ningún momento y que debes validarlo desde la red antes de poder volver a usarlo (de lo contrario, solo se "sugiere").

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 pequeña respuesta 304), pero tiene un costo de latencia, ya que el usuario aún debe ir a la red para averiguarlo. Y esta es la principal desventaja de este enfoque. Puede funcionar muy bien para las personas que tienen conexiones rápidas en el primer mundo y donde la CDN que elijas tiene una gran cobertura, pero no para las personas que tienen conexiones móviles más lentas o que usan una infraestructura deficiente.

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

Si bien sigo sugiriendo esta opción como una configuración predeterminada razonable, solo es eso: la configuración predeterminada. Sigue leyendo para descubrir cómo intervenir y actualizar los valores predeterminados.

URLs con huellas digitales

Si incluyes un hash del contenido del archivo en el nombre de los recursos, las imágenes, etcétera, que se publican en tu sitio, puedes asegurarte de que estos archivos siempre tengan contenido único, lo que generará archivos con nombres como sitecode.af12de.js, por ejemplo. Cuando tu servidor responde a las solicitudes de estos archivos, puedes configurar los navegadores de los usuarios finales para que los almacenen en caché durante mucho tiempo de forma segura con este encabezado:

Cache-Control: max-age=31536000,immutable

Este valor es un año, en segundos. Y, según las especificaciones, esto equivale a “para siempre”.

Es importante que no generes estos valores hash de forma manual, ya que es demasiado trabajo manual. Puedes usar herramientas como Webpack, Rollup, etcétera, para ayudarte con esto. Asegúrate de obtener más información sobre ellos en el Informe de herramientas.

Recuerda que no solo JavaScript puede beneficiarse de las URLs con huellas digitales. Los elementos como íconos, CSS y otros archivos de datos inmutables también se pueden nombrar de esta manera. (y 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 cambia tu sitio).

Independientemente de cómo tu sitio aborde el almacenamiento en caché, estos tipos de archivos con huellas digitales son muy valiosos para cualquier sitio que puedas compilar. La mayoría de los sitios no cambian en cada versión.

Por supuesto, no podemos cambiar el nombre de nuestras páginas "amigables" para los usuarios de esta manera: cambiar el nombre de tu archivo index.html a index.abcd12.html es inviable, no puedes decirles a los usuarios que vayan a una URL nueva cada vez que carguen tu sitio. Estas URLs "amigables" no se pueden cambiar de nombre ni almacenar en caché de esta manera, lo que me lleva a un posible punto medio.

El punto medio

Obviamente, hay espacio para un término medio en lo que respecta a la caché. Te presenté dos opciones extremas: almacenar en caché nunca o almacenar en caché para siempre. Además, habrá una serie de archivos que te gustaría almacenar en caché durante un tiempo, como las URLs "amigables" que mencioné anteriormente.

Si quieres almacenar en caché estas URLs "amigables" y su código HTML, vale la pena considerar qué dependencias incluyen, cómo se pueden almacenar en caché y cómo podría afectarte almacenar en caché sus URLs durante un tiempo. Analicemos una página HTML que incluya una imagen como la siguiente:

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

Si actualizas o cambias tu sitio borrando o cambiando esta imagen cargada de forma diferida, es posible que los usuarios que vean una versión almacenada en caché de tu HTML obtengan una imagen incorrecta o que no esté, ya que aún tendrán almacenada en caché la /images/foo.jpeg original cuando vuelvan a visitar tu sitio.

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

En general, la mayoría de las guías sobre el almacenamiento en caché hablarán sobre este tipo de configuración: si quieres almacenar en caché durante una hora, varias horas, etcétera. Para configurar este tipo de caché, usa un encabezado como este (que 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 artículos de noticias), creo que nunca debería almacenarse en caché y que deberías usar la configuración predeterminada que se indica más arriba. Creo que a menudo sobreestimamos el valor del almacenamiento en caché en comparación con el deseo del usuario de ver siempre el contenido más reciente y mejor, como una actualización importante sobre una noticia o un evento actual.

Opciones que no son HTML

Además del HTML, estas son algunas otras opciones para archivos que se encuentran en el punto medio:

  • En general, busca recursos que no afecten a otros.

    • Por ejemplo, evita CSS, ya que provoca cambios en la forma en que se renderiza el HTML.
  • Imágenes grandes que se usan como parte de artículos oportunos

    • Es probable que tus usuarios no visiten un artículo más de unas pocas veces, por lo que no debes almacenar en caché las fotos ni las imágenes hero para siempre y desperdiciar el almacenamiento.
  • Es un recurso que representa algo que tiene una 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.
    • Es posible que las compilaciones de un proyecto de código abierto tengan un límite de frecuencia, por lo que debes almacenar en caché una imagen del estado de compilación hasta que sea posible que cambie el estado.

Resumen

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

El almacenamiento en caché no es un concepto nuevo en la Web, pero quizás necesite una configuración predeterminada sensata. Considera usar una y habilitar de forma contundente mejores estrategias de almacenamiento en caché cuando las necesites. ¡Gracias por leer esta información!

Consulta también

Si quieres obtener una guía general sobre la caché HTTP, consulta Cómo evitar solicitudes de red innecesarias con la caché HTTP.