Jede Optimierung hinter einem perfekten Lighthouse-Score
Ich lasse Lighthouse ständig auf meiner Website laufen. Er bleibt bei jedem lokalen Durchlauf bei 100 und auch im Real Experience Score von Vercel bei 100.
Diese Scores stammen nicht von einer generischen Checkliste. Ich erreiche sie, indem ich die Arbeit vom Browser in die Build-Phase verschiebe.
Hier ist genau mein Vorgehen.
Arbeit in die Build-Zeit verlagern
Die meisten Anleitungen raten dazu, alles per Lazy-Loading zu laden. Ich bevorzuge Prerendering. Ich verwende TanStack Start mit aktiviertem Prerendering.
Dies verwandelt die gesamte Website während des Builds in statisches HTML. Der Browser muss kein schwerfälliges JavaScript ausführen, nur um die erste Seite anzuzeigen. Das HTML ist bereits vorhanden, wenn der Nutzer die Eingabetaste drückt.
Komplexe Logik vorab berechnen
Meine Homepage hat eine Weltkarte mit 5.000 Punkten. Normalerweise würde eine Library GeoJSON parsen und mathematische Berechnungen im Main Thread durchführen. Das blockiert die Seite für 1.000 ms.
Ich habe das gelöst, indem ich die Berechnungen in ein Build-Skript ausgelagert habe.
- Ich generiere einen einzigen SVG-Path-String für alle 5.000 Punkte.
- Ein einziger Pfad wird vom Browser viel schneller gerendert als 5.000 einzelne Kreise.
- Ich berechne Koordinaten-Lookup-Tabellen im Voraus, sodass der Browser zur Laufzeit keinerlei Berechnungen mehr durchführen muss.
Die Verzögerung von 1.000 ms wird zu einem einzigen, sofortigen Paint.
Font-Loading optimieren
Ich verwende rel="preload" für meine primären Fonts.
Ein häufiger Fehler ist das Vergessen des crossOrigin-Attributs. Wenn man es weglässt, lädt der Browser die Schriftart zweimal. Das ruiniert den Largest Contentful Paint (LCP). Ich lade nur die drei Fonts vorab, die "above the fold" verwendet werden.
Die richtigen Tools für Animationen nutzen
Ich verwende SMIL für einfache Puls-Animationen meiner Kartenmarkierungen. Das ist effizienter, als React-State zu nutzen, um eine Animationsschleife anzutreiben. Es ermöglicht dem Browser, die Arbeit auf dem Compositor-Thread zu erledigen.
Für komplexe Pfade verwende ich motion. Ich halte es einfach. Ich animiere einmal beim Mounten und vermeide es, auf Scroll-Positionen zu hören.
Bei Vektoren und WebP bleiben
Wenn es ein Logo oder eine Form ist, verwende ein SVG. Wenn es ein Foto ist, verwende WebP. Das hält die Dateigröße gering und verhindert Layout Shifts.
Over-Engineering vermeiden
Ich nutze kein Image-CDN. Ich nutze kein komplexes Code-Splitting. Meine Website ist klein, daher reicht Splitting auf Route-Ebene aus.
Ein perfekter Score kann eine Vanity Metric sein. Das eigentliche Ziel ist es, die Performance zu messen und so viel Arbeit wie möglich vom Gerät des Nutzers weg zu verlagern.
Mein Portfolio: brodin.dev
Quellcode: github.com/NathanBrodin/Portfolio
TanStack Start Prerendering: tanstack.com/start
Paper Shaders: shaders.paper.design
Vollständiger Post: https://dev.to/nathan-brodin/every-optimization-behind-a-perfect-lighthouse-score-283n
