Chaque optimisation derrière un score Lighthouse parfait
J'exécute Lighthouse sur mon site en permanence. Il reste à 100 lors de chaque exécution locale et à 100 dans le Real Experience Score de Vercel.
Ces scores ne proviennent pas d'une liste de contrôle générique. Je les obtiens en déplaçant la charge de travail du navigateur vers l'étape de build.
Voici exactement comment je m'y prends.
Déplacer le travail vers l'étape de build
La plupart des guides vous conseillent de tout charger en lazy-load. Je préfère le pré-rendu. J'utilise TanStack Start avec le pré-rendu activé.
Cela transforme l'ensemble du site en HTML statique pendant le build. Le navigateur n'a pas besoin d'exécuter du JavaScript lourd juste pour afficher la première page. Le HTML est déjà présent lorsque l'utilisateur appuie sur Entrée.
Pré-calculer la logique complexe
Ma page d'accueil contient une carte du monde avec 5 000 points. Habituellement, une bibliothèque analyserait le GeoJSON et effectuerait des calculs sur le thread principal. Cela bloque la page pendant 1 000 ms.
J'ai résolu ce problème en déplaçant les calculs vers un script de build.
- Je génère une seule chaîne de caractères SVG path pour les 5 000 points.
- Un seul chemin est bien plus rapide à rendre pour le navigateur que 5 000 cercles séparés.
- Je pré-calcule des tables de correspondance de coordonnées pour que le navigateur n'ait aucun calcul à effectuer au moment de l'exécution.
Le délai de 1 000 ms devient un rendu unique et instantané.
Optimiser le chargement des polices
J'utilise rel="preload" pour mes polices principales.
Une erreur courante est d'oublier l'attribut crossOrigin. Si vous l'omettez, le navigateur récupère la police deux fois. Cela ruine votre Largest Contentful Paint (LCP). Je ne précharge que les trois polices utilisées au-dessus de la ligne de flottaison (above the fold).
Utiliser les bons outils pour l'animation
J'utilise SMIL pour les animations de pulsation simples sur mes marqueurs de carte. C'est moins coûteux que d'utiliser l'état React pour piloter une boucle d'animation. Cela permet au navigateur de gérer le travail sur le thread de composition (compositor thread).
Pour les chemins complexes, j'utilise motion. Je reste simple. J'anime une seule fois au montage (on mount) et j'évite d'écouter les positions de défilement (scroll).
Privilégier les vecteurs et le WebP
S'il s'agit d'un logo ou d'une forme, utilisez un SVG. S'il s'agit d'une photo, utilisez le WebP. Cela permet de maintenir une taille de fichier faible et d'éviter les décalages de mise en page (layout shifts).
Éviter le sur-dimensionnement (over-engineering)
Je n'utilise pas de CDN d'images. Je n'utilise pas de code-splitting complexe. Mon site est petit, donc un découpage au niveau des routes (route-level splitting) est suffisant.
Un score parfait peut être une métrique de vanité. Le véritable objectif est de mesurer votre performance et de déplacer autant de travail que possible hors de l'appareil de l'utilisateur.
Mon Portfolio : brodin.dev
Code source : github.com/NathanBrodin/Portfolio
Pré-rendu TanStack Start : tanstack.com/start
Paper Shaders : shaders.paper.design
Article complet : https://dev.to/nathan-brodin/every-optimization-behind-a-perfect-lighthouse-score-283n
