Frontend-Entwicklungsleitfaden
Überblick
Dieser Leitfaden behandelt die moderne Frontend-Entwicklung mit React, Vue, Angular und Svelte, einschließlich Komponentenarchitektur, Leistungsoptimierung, Barrierefreiheit und Tests. Verwende ihn bei der Entwicklung von Webanwendungen, Komponentenbibliotheken oder der Optimierung der Frontend-Leistung.
Framework- und Layout-Entscheidungsregeln
- Wähle ein Framework basierend auf der Team-Expertise und den Projektanforderungen; standardmäßig React für ein breites Ökosystem, Vue für progressive Verbesserung bestehender Seiten, Svelte für Anwendungen, bei denen die Bundle-Größe kritisch ist, und Angular, wenn ein vollständiges, meinungsstarkes Framework mit integrierter Abhängigkeitsinjektion und Routing benötigt wird.
- Verwende CSS Grid für zweidimensionale Seitenlayouts und Flexbox für eindimensionale Komponentenausrichtung; vermeide absolute Positionierung für Layoutzwecke, da diese das responsive Reflow beeinträchtigt.
- Stelle beim Erstellen einer Komponentenbibliothek jede Komponente als benannten Export mit TypeScript-Props-Interface, einer Storybook-Story und einem Unit-Test bereit – Komponenten ohne alle drei werden nicht zusammengeführt.
- Zentralisiere bei der Integration mit Backend-APIs die Fetch-Logik in einer typisierten API-Client-Schicht (z. B. einem einzelnen Modul
api.ts, dasfetchoderaxiosmit Interceptors verwendet), damit Auth-Header, Fehlertransformationen und Wiederholungsversuche an einer Stelle behandelt werden.
Leistungs-Entscheidungsregeln
- Wenn der Largest Contentful Paint einer Seite in Lighthouse CI 2,5 Sekunden überschreitet, behandele dies als blockierenden Fehler – profiliere mit dem Chrome DevTools Performance-Tab und behebe den größten Engpass vor dem Merge.
- Verwende beim Hinzufügen von Animationen die CSS-Eigenschaften
transformundopacity(nur Compositor) anstelle vonwidth,heightodertop/left, um Layout-Neuberechnungen zu vermeiden, die Ruckeln verursachen. - Wenn die App Offline-Unterstützung benötigt, registriere einen Service Worker mit einer Cache-First-Strategie für statische Assets und einer Network-First-Strategie für API-Anfragen, mit Fallback auf zwischengespeicherte Antworten im Offline-Modus.
- Wenn das anfängliche JS-Bundle das Budget überschreitet (z. B. 200 KB gzip), füge routenbasiertes Code-Splitting mit
React.lazy()oder dynamischemimport()hinzu und verschiebe nicht-kritische Skripte unter den Fold. - Definiere bei der Unterstützung älterer Browser eine Browserslist-Konfiguration und lasse das Build-Tool (Vite, Webpack) automatisch polyfillen; füge keine manuellen Polyfills oder Feature-Checks hinzu, es sei denn, die Browserslist-Abdeckung ist unzureichend.
- Verwende beim Hinzufügen von Bildern
<picture>mit WebP/AVIF-Quellen und explizitenwidth/height-Attributen, um Layoutverschiebungen zu verhindern; füge für Bilder unter dem Foldloading="lazy"hinzu. - Wenn eine Route nicht beim initialen Seitenladen benötigt wird, umschließe sie mit
React.lazy()(oder Framework-Äquivalent) mit einem<Suspense>-Fallback, sodass das Haupt-Bundle den Code dieser Route ausschließt. - Konfiguriere beim Ausliefern statischer Assets den CDN oder Server so, dass
Cache-Control: public, max-age=31536000, immutablefür inhaltsgehashte Dateinamen undno-cachefürindex.htmlgesetzt wird.
Barrierefreiheits-Entscheidungsregeln
- Füge beim Erstellen interaktiver Komponenten ARIA-Attribute, Tastatur-Handler (nach Bedarf
Enter,Space,Escape) hinzu und teste mit axe-core, bevor die Aufgabe als abgeschlossen markiert wird. - Assoziiere beim Erstellen von Formularen jedes
<input>mit einem<label>überhtmlFor/id, stelle sichtbare Fehlermeldungen bereit, die mitaria-describedbyverknüpft sind, und stelle sicher, dass das Formular vollständig mit reiner Tastaturnavigation bedienbar ist. - Wenn Farbe zur Bedeutungsvermittlung verwendet wird (z. B. Fehlerzustände, Status-Badges), füge immer einen sekundären Indikator (Symbol, Text, Muster) hinzu, damit farbenblinde Benutzer die Zustände unterscheiden können.
- Wenn ein Modal oder Dropdown hinzugefügt wird, fange den Fokus innerhalb des Elements, während es geöffnet ist, und gib den Fokus beim Schließen an das auslösende Element zurück; teste durch Durchtabben des gesamten Ablaufs ohne Maus.
- Wenn ein Pull Request eine neue interaktive Komponente hinzufügt, muss der PR einen axe-core-Integrationstest enthalten, der null WCAG 2.1 AA-Verstöße bestätigt, bevor er gemergt werden kann.
CSS-Debugging-Entscheidungsregeln
Wenn ein Layout zerbricht, diagnostiziere nach Symptom:
- Flex-Child überläuft seinen Container: Füge
min-width: 0(Reihe) odermin-height: 0(Spalte) zum Flex-Child hinzu. Flex-Elemente standardmäßig aufmin-width: auto, was das Schrumpfen unter die Inhaltsgröße verhindert. - Grid-Elemente ignorieren Spaltenbreite: Verwende
minmax(0, 1fr)anstelle von1fr. Einfaches1frbedeutetminmax(auto, 1fr), was es dem Inhalt erlaubt, die Spalte breiter als beabsichtigt zu drücken. position: stickyhaftet nicht: Überprüfe jeden Vorfahren aufoverflow: hidden,overflow: autooderoverflow: scroll. Jeder dieser Werte erzeugt einen neuen Scroll-Kontext, der das sticky-Element enthält. Stelle auch sicher, dass das Element einentop/bottom-Wert gesetzt hat.- Mit
margin: autozentriertes Element wird nicht zentriert: Überprüfe, ob das Element eine explizitewidth(Block) hat oder der Elternteildisplay: flex(Flex-Child) hat.margin: autobewirkt nichts bei vollbreiten Blockelementen. z-indexfunktioniert nicht: Das Element benötigtposition: relative/absolute/fixed/sticky, um einen Stapelkontext zu erzeugen. Überprüfe auch, ob ein Vorfahre einen Stapelkontext erzeugt (übertransform,opacity < 1,filteroderwill-change), der den z-index-Bereich einschränkt.- Abstand zwischen inline-block/inline-Elementen: Leerzeichen in HTML erzeugen Lücken. Behebung: Verwende
display: flexauf dem Elternteil (bevorzugt) oder setzefont-size: 0auf dem Elternteil und setze es bei Kindern zurück. - 1px-Abstand zwischen benachbarten Elementen: Subpixel-Rendering. Behebung: Verwende
outlineanstelle vonborderzum Debugging oder setzebackgroundauf dem Elternteil, um die Lücke zu überdecken. - Textabkürzung mit Auslassungspunkten funktioniert nicht: Erfordert alle drei:
overflow: hidden,white-space: nowrap,text-overflow: ellipsis. Für mehrzeilige Abkürzung verwende-webkit-line-clampmitdisplay: -webkit-boxund-webkit-box-orient: vertical. - Container-Queries werden nicht angewendet: Überprüfe, ob der Vorfahre
container-type: inline-size(odersize) hat. Das Element selbst kann nicht sein eigener Container sein – die Query muss sich auf einen Elternteil beziehen.
Build-Tooling-Entscheidungsregeln
- Vite (Standard): Verwende für alle neuen Projekte. Instant-Dev-Server über natives ESM, schnelles HMR, Rollup-basierte Produktions-Builds. Wenn das Projekt CommonJS-only-Abhängigkeiten hat, die mit Vite fehlschlagen, füge
optimizeDeps.includefür diese Pakete hinzu – wechsle nicht zu Webpack. - Webpack: Verwende nur für bestehende Projekte, die es bereits verwenden, oder wenn ein bestimmtes Webpack-only-Plugin kein Vite-Äquivalent hat (selten). Migriere zu Vite, wenn sich die Gelegenheit bietet (siehe Migrations-Entscheidungsregeln).
- Turbopack: Verwende nur innerhalb von Next.js 14+ (
next dev --turbo). Noch nicht eigenständig verwendbar. Bietet schnellere Dev-Builds als Webpack für Next.js-Projekte. Wenn Builds bereits schnell sind (<5s), mache dir nicht die Mühe zu wechseln. - esbuild: Verwende zum Bündeln von Bibliotheken, Skripten oder CLI-Tools – nicht für vollständige Anwendungen. Keine HTML-Einstiegspunktbehandlung, kein Code-Splitting nach Route. Verwende
tsup(esbuild-Wrapper) zum Veröffentlichen von npm-Paketen. - SWC vs Babel: Verwende SWC (über Vite-Plugin oder Next.js-Standard). SWC ist 20-70x schneller für Transformationen. Verwende Babel nur, wenn ein Projekt von einem Babel-only-Plugin ohne SWC-Äquivalent abhängt (zunehmend selten).
- Monorepo-Tooling: <5 Pakete = npm/pnpm-Workspaces, kein zusätzliches Tool. 5-20 Pakete = Turborepo für Task-Caching. >20 Pakete oder polyglott = Nx. Füge niemals Monorepo-Tooling zu einem Ein-Paket-Projekt hinzu.
SSR- und Server-Komponenten-Entscheidungsregeln
Wann SSR vs CSR vs SSG verwendet werden soll
- SSG (Static Site Generation): Verwende für Inhalte, die sich weniger als einmal pro Stunde ändern (Marketingseiten, Dokumentation, Blog-Posts). Build bei der Bereitstellung. Schnellstmögliches TTFB.
- SSR (Server-Side Rendering): Verwende für personalisierte Inhalte (Dashboards, Benutzerprofile), SEO-kritische Seiten mit dynamischen Daten oder Seiten, bei denen veraltete Daten inakzeptabel sind. Fügt bei jeder Anfrage Server-Latenz hinzu – cache aggressiv mit
Cache-Controloder CDN. - CSR (Client-Side Rendering): Verwende für nur authentifizierte Seiten (Admin-Panels, interne Tools), bei denen SEO keine Rolle spielt und Interaktivität Priorität hat. Am einfachsten zu bauen und bereitzustellen (Statisches Hosting).
- ISR (Incremental Static Regeneration): Verwende für Seiten, die größtenteils statisch sind, aber regelmäßige Updates benötigen (Produktlisten, Preisseiten). Setze das
revalidate-Intervall basierend darauf, wie veraltet die Daten sein können: 60s für Preise, 3600s für Blog-Posts.
React Server Components (RSC) Entscheidungsregeln
- Standardmäßig Server-Komponenten: Jede Komponente ist eine Server-Komponente, es sei denn, sie benötigt Interaktivität. Wenn eine Komponente
onClick,useState,useEffectoder Browser-APIs hat – muss sie eine Client-Komponente sein ('use client'). - Datenabruf: Daten in Server-Komponenten mit
async/awaitdirekt abrufen – keinuseEffect, kein TanStack Query, keine Ladezustände erforderlich. Die Daten werden aufgelöst, bevor das HTML gesendet wird. - Auth in Server-Komponenten: Lies die Sitzung/das Cookie in einer Server-Komponente und übergib das Benutzerobjekt als Prop an Client-Komponenten. Lies niemals Cookies oder Sitzungen in Client-Komponenten – sie werden auf dem Client ausgeführt.
- Wann Server Actions vs API-Routen verwendet werden sollen: Verwende Server Actions (
'use server') für Formulareinreichungen und Mutationen, die von der UI aufgerufen werden. Verwende API-Routen (/api/*) für Webhooks, Drittanbieter-Integrationen oder Endpunkte, die von externen Diensten aufgerufen werden. - Teilen von Zuständen zwischen Server- und Client-Komponenten: Übergib serialisierbare Daten als Props von Server → Client. Wenn du einen clientseitigen Zustand benötigst, der von Serverdaten abgeleitet wird, initialisiere
useStatemit der Server-Prop und verwalte Aktualisierungen auf dem Client. - Große Datensätze: Streame mit
<Suspense>-Grenzen. Umschließe die langsame Server-Komponente in<Suspense fallback={<Skeleton />}>. Die Hülle wird sofort gerendert; die langsame Komponente streamt herein, wenn sie bereit ist. Platziere Suspense-Grenzen an sinnvollen UI-Abschnitten (Sidebar, Hauptinhalt, Kommentare) – nicht um jede Komponente.
Hydratationsfehler-Entscheidungsbaum
- Fehler: „Text content does not match“: Ein Wert unterscheidet sich zwischen Server- und Client-Rendering. Häufige Ursachen:
Date.now(),Math.random()odernew Date().toLocaleString()im Render → verschiebe inuseEffect+useState.- Bedingtes Rendern mit
typeof window !== 'undefined'→ verwendeuseEffect, um einhasMounted-Flag zu setzen. - Browser-Erweiterungen, die DOM-Knoten einfügen → nicht dein Fehler, aber teste im Inkognito-Modus, um zu bestätigen.
- Fehler: „Hydration failed because the server rendered HTML didn't match“: Ein struktureller Unterschied (unterschiedliche Elemente). Häufige Ursachen:
<p>verschachtelt in<p>oder<div>in<p>→ behebe die Verschachtelung, der HTML-Spezifikation erlaubt dies nicht.- Eine Drittanbieter-Komponente rendert auf dem Server anders als auf dem Client → umschließe mit
dynamic(() => import(...), { ssr: false }). - Fehlende schließende Tags oder selbstschließende Tags, wo HTML explizites Schließen erfordert.
Performance-Debugging-Workflow
Wenn eine Seite langsam ist, folge dieser Reihenfolge – überspringe keine Schritte:
Schritt 1: Identifiziere den Engpasstyp
- Führe Lighthouse aus. Überprüfe, welche Metrik fehlschlägt:
- LCP >2,5s: Das größte sichtbare Element lädt zu langsam. Gehe zu Schritt 2.
- FID/INP >200ms: Die Benutzerinteraktion wird durch JavaScript blockiert. Gehe zu Schritt 3.
- CLS >0,1: Layoutverschiebungen nach dem initialen Paint. Gehe zu Schritt 4.
Schritt 2: Behebe LCP
- Überprüfe, was das LCP-Element ist (Lighthouse zeigt es an). Normalerweise: Hero-Bild, Überschriftentext oder Video.
- Wenn Bild: Füge
priority(Next.js) oderfetchpriority="high"hinzu. Füge explizitewidth/heighthinzu. Liefere in WebP/AVIF aus. Wenn von einem CDN bereitgestellt, überprüfe die Cache-Header. - Wenn Text: Überprüfe auf render-blockierende Schriften. Verwende
font-display: swapoderfont-display: optional. Lade die kritische Schriftart mit<link rel="preload" as="font" crossorigin>vor. - Wenn durch JS blockiert: Das Bundle ist zu groß. Überprüfe Schritt 3. Das LCP-Element kann erst gerendert werden, wenn das JS, das es erstellt, geladen und ausgeführt wurde.
- Überprüfe die Server-Antwortzeit (TTFB). Wenn TTFB >600ms, liegt der Engpass im Backend oder CDN – nicht im Frontend.
Schritt 3: Behebe INP (Interaction to Next Paint)
- Öffne Chrome DevTools → Performance → zeichne eine Klick-/Eingabeinteraktion auf.
- Finde die Long Task (>50ms gelber Balken). Klicke darauf, um den Aufrufstapel zu sehen.
- Wenn die Long Task dein Code ist: Zerlege die Arbeit in kleinere Teile mit
requestIdleCallback,scheduler.yield()(Chrome 115+) odersetTimeout(fn, 0), um die Kontrolle zwischen den Frames an den Browser abzugeben. - Wenn die Long Task React-Neu-Rendering ist: Öffne React DevTools Profiler. Finde die Komponente, die neu rendert. Häufige Behebungen:
React.memo(teure Kinder),useMemo(abgeleitete Werte) oder verschiebe den Zustand näher an die Stelle, wo er verwendet wird. Wenn >500 Komponenten bei einer einzigen Zustandsänderung neu rendern, ist der Zustand zu weit oben im Baum. - Wenn die Long Task ein Drittanbieter-Skript ist (Analytics, Werbung): Verschiebe mit
asyncoderdefer-Attribut oder lade nachrequestIdleCallback.
Schritt 4: Behebe CLS
- Überprüfe, welches Element sich verschiebt (Lighthouse zeigt es an, oder verwende DevTools → „Layout Shift Regions“).
- Bild/Video ohne Abmessungen: Füge
width- undheight-Attribute (oderaspect-ratioCSS) hinzu. Der Browser reserviert Platz, bevor das Asset geladen wird. - Schriftwechsel: Die Fallback-Schrift hat andere Metriken als die Webschrift. Verwende
size-adjustin@font-face, um die Metriken anzupassen, oder verwendefont-display: optional, um den Wechsel vollständig zu eliminieren. - Dynamischer Inhalt, der über dem Fold injiziert wird: Werbung, Banner, Cookie-Hinweise. Reserviere Platz mit
min-heightauf dem Container. Wenn die Inhaltshöhe variiert, verwendecontain: layout, um zu verhindern, dass sich Verschiebungen ausbreiten. - Nachladendes CSS: Wenn ein Stylesheet nach dem ersten Paint geladen wird und das sichtbare Layout ändert, inline das kritische CSS oder lade das Stylesheet vor.
Code-Qualitäts-Entscheidungsregeln
- Stelle beim Schreiben von Tests sicher, dass jede Komponente mindestens einen Unit-Test für ihren primären Renderpfad und einen Interaktionstest (Klick, Tastatur) hat – erzwinge dies über eine CI-Coverage-Gate von mindestens 80% Zeilenabdeckung.
- Aktiviere beim Starten eines Projekts
strict: trueintsconfig.jsonvon Tag eins an; das nachträgliche Einführen des Strict-Modus ist exponentiell schwieriger, je größer die Codebasis wird. - Zeige bei Fehlschlagen eines API-Aufrufs oder einer asynchronen Operation eine benutzersichtbare Fehlermeldung mit einer Wiederholungsaktion an – schlucke Fehler niemals stillschweigend oder zeige rohen Ausnahmetext an.
…
[gekürzt für die Übersetzung]