Expertise · Performance web
Un score Lighthouse donne un indice, mais n’explique pas pourquoi une page paraît lente à de vrais utilisateurs. Pour agir, il faut relier les signaux terrain au travail du navigateur et, lorsque l’instrumentation le permet, au chemin serveur.
Le point de départ
Une application rapide au bureau, irrégulière sur le terrain
Dans ce scénario, une application Next.js sert des pages publiques et un espace connecté. Les tests locaux semblent corrects, mais le support remonte des interactions lentes sur mobile et les Core Web Vitals varient fortement d’une route à l’autre.
L’équipe a déjà appliqué les optimisations évidentes. Ajouter une checklist ne dira pas où le temps est réellement perdu ; l’audit part donc d’une expérience observée pour remonter jusqu’à une cause vérifiable.
Le mandat
Donner à l’équipe un langage commun et une méthode de diagnostic qu’elle pourra réutiliser.
- Segmenter les mesures terrain par route, build, segment mobile ou desktop et type de navigation.
- Mettre en regard une interaction lente, les tâches du navigateur et, si un identifiant est propagé, la trace serveur correspondante.
- Corriger un goulot démontré avant d’ajouter de nouveaux dashboards.
L’investigation
Commencer par une expérience précise, pas par la moyenne du site
Nous choisissons un parcours touché : ouvrir une fiche, modifier un filtre, puis afficher les résultats. Les données terrain indiquent quelle population rencontre la dégradation ; un test contrôlé rejoue ensuite la séquence avec un profil réseau et CPU représentatif.
Un INP dégradé peut venir d’un rendu React coûteux, d’une long task ou d’un script tiers. Un LCP tardif peut dépendre du temps serveur, de la découverte de la ressource ou de son décodage. La métrique resserre l’enquête, mais ne désigne pas seule le responsable.
Population touchée
La dégradation concerne-t-elle une route, un segment mobile ou desktop, une région ou un build précis ?
Moment utilisateur
Quel élément devient le LCP, et quelle interaction produit l’INP observé ?
Travail du navigateur
Le main thread exécute-t-il du JavaScript, un rendu React, du layout ou un script tiers ?
Chemin serveur
Sur une requête instrumentée, où le temps est-il passé : Next.js, l’API, la base ou un service externe ?
L’investigation aboutit à une hypothèse testable pour une population et une action données. Une correction ciblée ne prétend pas accélérer toutes les pages.
Le dispositif de mesure
Préserver le contexte sans inventer de corrélation
Une mesure terrain devient exploitable avec une route normalisée, un build, une catégorie de viewport (mobile ou desktop), un type de navigation, un identifiant de page et des horodatages. Ces dimensions permettent de retrouver le bon segment sans collecter de données personnelles inutiles.
Elles ne prouvent pas qu’un Web Vital correspond à un span précis. Une liaison exacte exige un identifiant généré côté serveur, transmis au navigateur puis réutilisé sur les requêtes concernées. Sans cette propagation, les traces Next.js et OpenTelemetry restent utiles pour comparer la même route, le même build et la même fenêtre temporelle, mais cette comparaison doit être présentée comme telle.
Mesure terrain
LCP, INP et CLS avec route, build, viewport et navigation.
Diagnostic navigateur
Long tasks, rendu React, layout et scripts tiers expliquent le travail côté client.
Traces serveur
Rendu, accès aux données et dépendances sont filtrés sur le même segment.
Hypothèse vérifiable
Une cause candidate, une modification et le signal qui doit évoluer.
import { onCLS, onINP, onLCP, type Metric } from 'web-vitals'
let registered = false
type ViewportClass = 'mobile' | 'desktop'
function getViewportClass(): ViewportClass {
return matchMedia('(max-width: 767px)').matches
? 'mobile'
: 'desktop'
}
export function registerWebVitals(normalizedRoute: string) {
if (registered) return
registered = true
const pageId = crypto.randomUUID()
const report = (metric: Metric) => {
const payload = {
route: normalizedRoute,
build: process.env.NEXT_PUBLIC_BUILD_ID ?? 'dev',
viewport: getViewportClass(),
navigation: metric.navigationType,
pageId,
pageStartedAt: performance.timeOrigin,
reportedAt: new Date().toISOString(),
metric: {
id: metric.id,
name: metric.name,
value: metric.value,
rating: metric.rating,
},
}
const body = new Blob([JSON.stringify(payload)], {
type: 'application/json',
})
navigator.sendBeacon('/api/vitals', body)
}
onCLS(report)
onINP(report)
onLCP(report)
}Ce callback s’enregistre une fois par chargement de document ; ce snippet ne mesure pas séparément chaque navigation client de l’App Router. L’identifiant de build doit être injecté au déploiement. Un bon diagnostic dépend de dimensions cohérentes et d’un niveau de certitude annoncé honnêtement.
La réalisation
Cinq étapes pour passer du signal à une correction
L’audit avance parcours par parcours. Chaque étape produit un artefact que l’équipe peut relire ou mesurer : segment, capture de trace, hypothèse, diff ou résultat en production.
01
Qualifier le signal terrain
Vérifier la collecte, séparer les routes et isoler la population concernée.02
Reproduire le parcours
Utiliser un scénario stable, un profil d’appareil crédible et le même build.03
Localiser le temps perdu
Croiser flame chart, React Profiler et spans serveur lorsque la requête est instrumentée.04
Traiter une cause
Réduire une long task, déplacer un calcul, corriger une cascade de requêtes ou prioriser une ressource.05
Mesurer après livraison
Comparer le même segment sur le nouveau build et conserver un garde-fou adapté.
Si le signal attendu ne bouge pas, l’hypothèse est rejetée et documentée. L’équipe évite ainsi de répéter une optimisation séduisante mais inefficace.
Les résultats qualitatifs
Une performance discutée à partir de parcours, pas d’impressions
Produit, design et développement partagent les mêmes repères. Une alerte précise la population et l’action touchées ; une PR annonce le signal attendu. Le support peut transmettre la route, le build et la catégorie mobile ou desktop sans demander à l’utilisateur d’ouvrir DevTools.
Ce que l’équipe peut vérifier
Une méthode de diagnostic commune, réutilisable après chaque livraison.
- Une régression terrain peut être rattachée à une route, un build et une population.
- Sur les requêtes instrumentées, les traces séparent le rendu du temps passé dans les dépendances lorsque celles-ci émettent leurs propres spans.
- Chaque optimisation importante part d’une hypothèse falsifiable.
- Les dashboards sans usage peuvent être retirés sans perdre la méthode de diagnostic.
À retenir
Les Core Web Vitals décrivent une expérience, pas la ligne de code responsable. L’audit conserve assez de contexte pour formuler une cause, la tester et mesurer le résultat.
Sources et documentation
- Web Vitals. web.dev. Définition officielle des Core Web Vitals et de leur mesure terrain.
- OpenTelemetry avec Next.js. Documentation Next.js. Guide officiel sur les traces et les spans personnalisés.
- Performance measurement APIs. Documentation Node.js. Référence officielle des API de mesure du runtime Node.js.
