← Retour au blog
Core Web VitalsLCP optimizationAngular performanceSPA optimizationWeb performance

Core Web Vitals : optimiser le LCP d'une SPA Angular en production

Le LCP mesure le temps d'affichage du plus grand élément visuel dans le viewport. Pour une Single Page Application Angular, c'est un défi spécifique : le bundle JavaScript doit être téléchargé, parsé et exécuté avant même que le DOM commence à se construire. Contrairement à une application serveur-renderedée, une SPA pure démarre de zéro côté client. Cette réalité technique explique pourquoi tant d'applications Angular affichent des LCP > 2.5s en production, déclassant la note Core Web Vitals et impactant le ranking SEO Google.

Comprendre l'architecture du problème

Une SPA Angular classique charge d'abord main.js (souvent 150 à 300 Ko minifiés+gzippés), puis exécute le code d'initialisation, crée les composants racine et enfin peint le contenu. Si ce main.js contient la totalité de l'application, y compris des routes rarement visitées, le navigateur doit tout parser avant de pouvoir afficher quoi que ce soit. Le LCP ne démarre réellement que lorsque le premier élément « important » (headline, image, bloc de texte) s'affiche. Pour une app e-commerce, ce peut être l'image du produit ou le titre ; pour un dashboard, c'est souvent un graphique ou une table. Le problème : si cet élément dépend du JavaScript applicatif, vous êtes limité par la vitesse d'exécution du bundle.

Route-based code-splitting : la fondation

Angular CLI génère automatiquement un bundle par route lazy-loaded, mais beaucoup d'équipes ne l'exploitent pas vraiment. Configurez votre routing avec loadChildren (ou loadComponent en Angular 14+) et mesurez la taille réelle des chunks produits. Par exemple, un module dashboard ne devrait jamais être inclus dans le bundle principal si l'utilisateur arrive d'abord sur la homepage. ng build --stats-json génère un rapport JSON que vous pouvez analyser avec webpack-bundle-analyzer . Si votre main.js dépasse 100 Ko gzippé, c'est un signal d'alerte. Utilisez NgModule avec preloadingStrategy: PreloadAllModules uniquement si votre connexion réseau le permet ; préférez NoPreloading ou une stratégie custom basée sur les interactions utilisateur.

Images : LCP critique et optimisation réseau

Si votre LCP est une image (cas fréquent), trois leçons s'appliquent. Première : utilisez les formats modernes (WebP avec fallback JPEG) et la balise <picture> avec srcset pour adapter à la densité d'écran et la largeur du viewport. Deuxième : chargez l'image critique en priorité haute. Dans Angular, injectez NgOptimizedImage avec priority="true" sur l'image LCP détectée. Cela ajoute fetchpriority="high" au HTML et améliore sensiblement le téléchargement. Troisième : dimensionnez correctement. Une image servie en 1920px mais affichée en 400px consomme bande passante inutilement. Utilisez un service CDN (Cloudinary, Imgix) ou un ImageOptimizationService custom qui génère des sources responsive. Exemple concret : remplacer <img src="product.jpg"> par <img ngSrc="product.jpg" priority [width]="600" [height]="400" sizes="(max-width: 768px) 100vw, 600px"> réduit le LCP de 300ms à 800ms selon la connexion réseau.

Réduire le JavaScript critique du bundle

Même avec code-splitting, le code d'initialisation Angular (zone.js, compiler, change detection) représente 50 à 70 Ko. Optimisez ce qui est inévitable. Utilisez bundlebudgets dans angular.json pour forcer une limite stricte : "maximumError": "100kb" sur main. Testez ng build --configuration production et analysez avec source-map-explorer pour identifier les dépendances cachées. Souvent, un import mal placé charge un module entier inutilement. Exemple : importer HttpClientModule dans le root module alors qu'une seule route l'utilise. Optez plutôt pour l'injection standalone et les imports localisés. Utilisez aussi @angular/platform-browser en mode ngZone.runOutsideAngular() pour les tâches non-UI (timers, event listeners) qui ne doivent pas déclencher la détection de changement. Cela réduit le temps d'initialisation de 100ms à 200ms sur certaines apps.

Piège courant : penser que le preloading résout tout

Une erreur répandue est d'activer PreloadAllModules en production pour « rendre l'app plus rapide ». En réalité, cela télécharge tous les bundles lazy au lieu d'attendre que l'utilisateur les demande. Sur une connexion 4G lente ou mobile, cela bloquerait le LCP du bundle principal. Le preloading n'a de sens que pour les routes très probables (détectées par analytics) et avec une stratégie intelligente. Mieux vaut un LCP rapide et une navigation légèrement plus lente au premier clic qu'un LCP lent mais des transitions fluides. Priorité absolue : LCP < 2.5s. Tout le reste est secondaire.

Monitoring en production et ajustements continus

Configurez Google Analytics 4 avec Web Vitals pour suivre le LCP réel des utilisateurs. web-vitals npm package offre une API simple : import { getLCP } from 'web-vitals'; getLCP(console.log); . Envoyez ces données à votre backend ou à un service comme Sentry, DataDog ou Cloudflare Analytics. Segmentez par connexion réseau (4g, 3g, slow-2g via navigator.connection.effectiveType ) et par device (mobile vs desktop). Les métriques synthétiques (Lighthouse) ne reflètent pas la réalité : un utilisateur sur 4G avec un iPhone 11 affichera un LCP bien différent d'une machine de développement en WiFi. Créez un dashboard de suivi : si le LCP 75e percentile dépasse 2.5s, déclenchez une alerte. Chaque optimisation doit être validée en production sur 5000+ sessions avant conclusion.

Optimiser le LCP d'une SPA Angular exige une approche systématique : code-splitting par route, images responsives avec priorité haute, réduction du JavaScript critique et monitoring continu. Il n'existe pas de solution unique, mais une accumulation de micro-optimisations qui, ensemble, transforment une app de 4s LCP en 1.8s. Commencez par mesurer votre baseline avec PageSpeed Insights et web-vitals , identifiez le goulot (bundle ou image), appliquez une optimisation, puis mesurez à nouveau. Répétez ce cycle chaque sprint. Le LCP n'est pas un problème technique isolé : c'est un indicateur de la qualité globale de l'architecture frontend.

Développeur Angular & Mobile freelance — Strasbourg.

© 2026 Emilien Pons — Tous droits réservés.Conçu avec Angular, PrimeNG et ❤️