Cómo medir las CWVs en SPAs

Esta página también está disponible en: English

Tiempo de lectura: 8 mins

Una de las preguntas más difíciles de responder cuando se habla de Core Web Vitals es cómo medirlas en una Single-Page Application (SPA). En este artículo, aclararé los cuellos de botella y el estado actual de este tema.

Pero antes de entrar en detalles, hablemos de las soft navigations. Una soft navigation hace referencia a la transición fluida entre páginas web, en la que una nueva página no se carga por completo, sino que se modifica mediante JavaScript. Aunque esta técnica se ha hecho bastante popular recientemente a través de varios frameworks, existen limitaciones en cómo afecta a las Core Web Vitals.

Las Core Web Vitals son un conjunto de métricas que Google utiliza para medir la performance de los sitios web, incluida la velocidad de carga, la interactividad y la estabilidad visual. Estas métricas son vitales porque afectan a la experiencia de usuario del sitio web y, potencialmente, a los resultados de búsqueda en el buscador de Google. Google introdujo las Core Web Vitals en mayo de 2020 y, desde entonces, se han convertido en un factor importante en el desarrollo web.

Desafíos

Tal y como he mencionado antes, aunque las SPAs pueden ofrecer una experiencia más fluida, crean desafíos a la hora de medir Core Web Vitals. Por ejemplo, una página SPA puede tener varias opciones de navegación, en las que el usuario puede hacer clic para acceder a diferentes partes de la aplicación. Con las soft navigations, estas opciones no se consideran páginas únicas, y cada clic simplemente carga nuevo contenido en la página actual. La URL puede modificarse mediante JavaScript, emulando la navegación de las multi-page applications (MPA), pero el navegador las considera actualizaciones de la página actual, en lugar de páginas nuevas.

El Chrome User Experience Report (CrUX) se basa en "hard" navigations. Esto significa que las métricas como FCP, LCP o FID sólo se reportarán para la primera página vista. Otras métricas como CLS o INP se miden durante todo el ciclo de vida de una página. Por lo tanto, se pueden recopilar nuevos valores de CLS e INP, pero se asignarán a la primera página vista, incluso si se producen después de una o varias soft navigations. Además, sólo se obtiene un valor global para CLS e INP, en lugar de un valor por cada página de la aplicación.

Para solventar estas limitaciones, los desarrolladores pueden adoptar distintas estrategias para garantizar unas mediciones de Core Web Vitals más útiles. Una opción consiste en crear métricas personalizadas que midan con precisión la experiencia del usuario en las SPAs.

Los desarrolladores también pueden considerar el uso de otras opciones de renderizado, como el Server Side Rendering (SSR) o los Static Site Generators (SSG) para superar algunas de las limitaciones de las SPAs. Con estas arquitecturas, los desarrolladores pueden garantizar "hard" navitagions a los usuarios y evitar todos los inconvenientes de las SPAs a la hora de medir las CWVs.

Sin embargo, estas opciones no siempre son posibles.

Activar las soft navigations en Chrome (experimental)

Desde Chrome 110, puedes habilitar las soft navigations y empezar a medir las Core Web Vitals. De acuerdo con la documentación de Chrome, puedes habilitarlo de dos formas distintas:

Nota: Los sitios web que deseen activar esta función para que todos sus visitantes vean el impacto, disponen de una versión de prueba de Chrome 110 a Chrome 112 que puede activarse suscribiéndose a la versión de prueba e incluyendo un meta tag con el token de prueba de origen en la cabecera HTML o HTTP.

Midiendo las Core Web Vitals en soft navigations

Tras activar el flag de Experimental Web Platform features, podrás ver la siguiente información en la consola de Chrome después de cada soft navigation:

  A soft navigation has been detected: https://example.com/page

Y ahora ya está casi todo listo para empezar a medir las CWVs para cada soft navigation.

Utilizando un PerformanceObserver

Si unas un PerformanceObserver, debes incluir includeSoftNavigationObservations: true en tu llamada observe. Por ejemplo, este sería un ejemplo básico para mostrar el LCP en la consola:

  new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
console.log('LCP candidate:', entry.startTime, entry);
}
}).observe({type: 'largest-contentful-paint', buffered: true, includeSoftNavigationObservations: true});

Una vez has implementado esto, verás los distintos LCP candidates para cada soft navigation en la consola. Algo parecido a esto:

  A soft navigation has been detected: https://www.example.com/page2
LCP candidate: 6054.2999
▶ LargestContentfulPaint {renderTime: 6054.299, loadTime: 0, size: 3591, id: '', url: '', ...}
LCP candidate: 6177.7999
▶ LargestContentfulPaint {renderTime: 6177.799, loadTime: 6155, size: 166500, id: '', url: 'https://www.example.com/image.jpg', ...}

Para cada LCP candidate, obtendrás un objeto con los todos los detalles asociados, como el elemento HTML, URL (si el LCP candidate es un archivo externo), loadTime y tamaño, entre otros.

Además del LCP, puedes utilizar un PerformanceObserver para mostrar los detalles para otras web vitals. Por ejemplo, el siguiente código mostrará los detalles para el CLS en la consola:

  let clsValue = 0;
let clsEntries = [];

let sessionValue = 0;
let sessionEntries = [];

new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
// Only count layout shifts without recent user input.
if (!entry.hadRecentInput) {
const firstSessionEntry = sessionEntries[0];
const lastSessionEntry = sessionEntries[sessionEntries.length - 1];

// If the entry occurred less than 1 second after the previous entry and
// less than 5 seconds after the first entry in the session, include the
// entry in the current session. Otherwise, start a new session.
if (sessionValue &&
entry.startTime - lastSessionEntry.startTime < 1000 &&
entry.startTime - firstSessionEntry.startTime < 5000) {
sessionValue += entry.value;
sessionEntries.push(entry);
} else {
sessionValue = entry.value;
sessionEntries = [entry];
}

// If the current session value is larger than the current CLS value,
// update CLS and the entries contributing to it.
if (sessionValue > clsValue) {
clsValue = sessionValue;
clsEntries = sessionEntries;

// Log the updated value (and its entries) to the console.
console.log('CLS:', clsValue, clsEntries)
}
}
}
}).observe({type: 'layout-shift', buffered: true, includeSoftNavigationObservations: true});

Usando web-vitals.js

Una forma más sencilla es utilizar la librería web-vitals.js para medir las CWVs, que se encarga de muchos de los cálculos que pueden ser necesarios a partir de las entries del PerformanceObserver, como se muestra en el ejemplo anterior del CLS. Para ello, usa la rama soft-navs e incluye {reportSoftNavs: true} en las llamadas a las funciones. Por ejemplo, este código básico serviría para mostrar el FCP, el LCP y el CLS:

  import {
onFCP,
onLCP,
onCLS
} from 'web-vitals'

onFCP(({value}) => console.log('FCP: ', value), {reportSoftNavs: true});
onLCP(({value}) => console.log('LCP: ', value), {reportSoftNavs: true});
onCLS(({value}) => console.log('CLS: ', value), {reportSoftNavs: true});

Tras implementarlo, obtendrás este tipo de información en la consola de Chrome:

  A soft navigation has been detected: https://www.example.com/page2
CLS: 0.00192837465
FCP: 32.6739203094
LCP: 803.83929999

La librería web-vitals actualmente reporta las siguientes métricas para las soft navigations:

Conclusiones

Este es un experimento muy emocionante para empezar a medir una arquitectura muy común en el desarrollo web actual y que hoy en día no está en CrUX. Es un primer paso pero, de nuevo, es todavía un experimento. Sin embargo, Google está recopilando información sobre el mismo. Así que, si estás probando este enfoque, no dudes en compartir tus comentarios con ellos: