Warum Performance ein Feature ist
Performance ist kein letzter Feinschliff am Ende eines Projekts. Sie entscheidet darüber, ob Nutzer deine Inhalte überhaupt sehen. Eine Seite, die vier Sekunden benötigt, um ihren Hauptinhalt anzuzeigen, verliert einen Großteil ihrer Besucher, noch bevor sie nutzbar ist. Zudem lassen langsame Interaktionen eine App defekt wirken, selbst wenn sie technisch einwandfrei funktioniert.
Die gute Nachricht ist, dass Performance messbar und größtenteils systematisch ist. Eine kleine Anzahl an Hebeln – weniger laden, später laden, weniger Arbeit auf dem Main Thread verrichten – ist für die allermeisten Optimierungserfolge verantwortlich. Dieser Guide behandelt die Metriken, die Tools und die Techniken, die am wichtigsten sind.
Core Web Vitals
Drei Metriken, die zusammen als Core Web Vitals bezeichnet werden, beschreiben die User Experience:
- Largest Contentful Paint (LCP) — der Zeitpunkt, an dem das größte sichtbare Element fertig gerendert ist. Ein guter Wert liegt unter 2,5 Sekunden.
- Interaction to Next Paint (INP) — die Latenz zwischen einer Benutzerinteraktion und dem nächsten visuellen Update. Ein guter Wert liegt unter 200 Millisekunden.
- Cumulative Layout Shift (CLS) — wie stark sich sichtbare Inhalte unerwartet verschieben. Ein guter Wert liegt unter 0,1.
Ergänzende Metriken sind Time to First Byte (TTFB) für die Server-Latenz und First Contentful Paint (FCP) für den Zeitpunkt, an dem die ersten Inhalte erscheinen. Zusammen geben sie Aufschluss darüber, ob eine Seite schnell, reaktionsschnell und stabil ist.
Messen
Sie benötigen sowohl Felddaten (Field Data) als auch Labordaten (Lab Data).
Felddaten stammen von echten Nutzern und spiegeln die tatsächliche Vielfalt an Geräten und Netzwerken wider. Das ist der Wert, auf den Sie optimieren. Labordaten aus Lighthouse oder den DevTools sind reproduzierbar, was sie besser für die Diagnose spezifischer Probleme macht.
Der Browser stellt echte Zeitmessungen über die Performance API zur Verfügung.
// observe.js
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(entry.name, entry.startTime);
}
}).observe({ type: "largest-contentful-paint", buffered: true });
Bibliotheken wie web-vitals kapseln diese Observer und melden die Daten an Ihre Analytics-Tools, sodass Sie Felddaten erhalten, ohne die gesamte Infrastruktur selbst aufbauen zu müssen.
Weniger laden
Der effektivste Hebel ist es, weniger zu übertragen. JavaScript ist die kostspieligste Ressource, da sie heruntergeladen, geparst und ausgeführt werden muss und zudem mit dem Rendering um den Main Thread konkurriert.
- Entfernen Sie ungenutzte Dependencies und bevorzugen Sie kleinere Alternativen.
- Importieren Sie aus einer Library nur die Funktionen, die Sie tatsächlich verwenden.
- Splitten Sie Routen und rechenintensive Features mittels dynamischer
import(). - Rendern Sie, wo immer möglich, auf dem Server und übertragen Sie nur die interaktiven Teile.
- Komprimieren Sie Dateien und nutzen Sie moderne Formate wie Brotli und AVIF.
- Legen Sie ein Bundle-Budget fest und lassen Sie die CI fehlschlagen, wenn dieses überschritten wird.
Ein Bundle-Analyser zeigt Ihnen genau, was in Ihrem Build enthalten ist – was beim ersten Mal meistens überraschend ist.
Späteres Laden
Nicht alles wird für den ersten Paint benötigt. Verschieben Sie den Rest auf einen späteren Zeitpunkt.
<!-- deferred.js -->
<script src="app.js" defer></script>
<script src="analytics.js" async></script>
<img src="hero.avif" fetchpriority="high" alt="Hero" />
<img src="thumb.avif" loading="lazy" decoding="async" width="400" height="300" alt="" />
defer führt Scripte nach dem Parsing aus, async führt sie aus, sobald sie heruntergeladen wurden, fetchpriority="high" priorisiert das LCP-Bild und loading="lazy" verzögert das Laden von Bildern außerhalb des sichtbaren Bereichs. Dynamisches import() bewirkt dasselbe für JavaScript-Module.
Rendering und Stabilität
Zwei Rendering-Probleme dominieren den CLS und die wahrgenommene Geschwindigkeit.
Reservieren Sie Platz für Bilder, iframes, Anzeigen und Embeds, damit diese den Inhalt nicht verschieben. Setzen Sie width und height oder verwenden Sie aspect-ratio in CSS. Nutzen Sie eine Font-Strategie, die einen späten Swap vermeidet, wie zum Beispiel font-display: swap mit einem passenden Fallback oder self-hosted Fonts.
Halten Sie den Main Thread frei. Lange Tasks blockieren die Interaktion und verschlechtern den INP. Teilen Sie aufwendige Aufgaben auf, lagern Sie rechenintensive Berechnungen in einen Web Worker aus und vermeiden Sie Layout Thrashing, indem Sie DOM-Reads und -Writes bündeln.
Caching
Caching verwandelt wiederholte Besuche in sofortige Ladevorgänge. Nutzen Sie Content-Hashes für das Fingerprinting von Assets und liefern Sie diese mit einem langen Cache-Control max-age aus, da eine geänderte Datei einen neuen Namen erhält. Servieren Sie HTML mit einem kurzen Cache und einer Revalidierung. Für die Offline-Verfügbarkeit und die Geschwindigkeit bei wiederholten Besuchen kann ein Service Worker die App Shell und Assets cachen, wie im PWA-Guide beschrieben.
Performance-Budgets
Ein Budget macht Performance zu einer verbindlichen Vorgabe statt zu einem bloßen Wunsch.
{
"budgets": [
{ "path": "/*", "resourceSizes": [{ "resourceType": "script", "budget": 170 }] }
]
}
Legen Sie ein realistisches Limit für JavaScript, Bilder und LCP fest und setzen Sie dieses in der CI durch. Wenn ein Pull Request das Budget überschreitet, schlägt der Build fehl und der Autor muss entscheiden, ob der Trade-off gerechtfertigt ist. So verhindern Teams, dass die Performance im Laufe der Zeit schleichend abnimmt.
Best Practices
- Messen Sie, bevor Sie optimieren, und nutzen Sie sowohl Field- als auch Lab-Daten.
- Liefern Sie weniger JavaScript aus, bevor Sie andere Mikro-Optimierungen vornehmen.
- Nutzen Sie Lazy-Loading für Bilder unterhalb des Sichtfelds (below-the-fold) und splitten Sie umfangreiche Routes.
- Legen Sie explizite Dimensionen für Medien fest, um den CLS zu schützen.
- Setzen Sie
fetchpriority,deferundasyncbewusst ein. - Nutzen Sie Fingerprinting für Assets und cachen Sie diese langfristig.
- Legen Sie ein Bundle-Budget fest und setzen Sie dieses in der CI durch.
Häufige Fehler
- Optimierung der falschen Dinge ohne vorherige Messung.
- Auslieferung eines riesigen Client-Bundles für Inhalte, die statisch sein könnten.
- Übereiliges Laden aller Bilder und Scripte (Eager Loading).
- Fehlende Bilddimensionen, die zu Layout Shifts führen.
- Blockieren des Main Threads durch lange synchrone Tasks.
- Performance als einmaliges Projekt statt als kontinuierliches Budget zu betrachten.
Wie geht es weiter?
Performance ist eine Disziplin, keine Checkliste. Nutzen Sie Vite, um Ihr Bundle aufzuteilen und zu analysieren, reduzieren Sie das JavaScript-Gewicht mit den Mustern aus dem React-Guide, implementieren Sie Offline-Caching mit PWA und halten Sie den Main Thread mit solidem JavaScript frei. Messen Sie anschließend Ihre eigene Seite mit Felddaten und entscheiden Sie sich für die eine Änderung, die den größten Effekt hat.