React-Frontend
Regeln für jedes React-Frontend. Diese Datei enthält, was immer gilt; lies die passende Referenz bevor du an diesem Thema arbeitest.
| Aufgabe | Lies |
|---|---|
| Ordner, Layer, Slices, öffentliche API, Imports, Barrel-Dateien | references/structure.md |
| FSD-Tiefenbohrungen: Entscheidungsbaum, Cross-Imports, Entitäten, Assets, Auth/API-Platzierung, Framework-Verdrahtung, Migration | references/fsd/ (Index am Ende von structure.md) |
| Benennung, Dateigröße, Props, Designsystem, Layouts, Konstanten | references/code-style.md |
| Komponenten, Hooks, Effekte, Memoization, Übergänge, lange Listen, Hydration | references/hooks-and-rendering.md |
| Wasserfälle, Bundle-Größe, Code-Splitting, Vorladen, Re-Render-Kosten | references/performance.md |
| Serverdaten, Queries, Mutationen, Loader, Suchparameter, Zustand | references/data-and-state.md |
| Formulare, Validierung, Formularfehler | references/forms.md |
| Semantik, Tastatur, Fokus, Kontrast, Live-Regionen, A11y-Tests | references/accessibility.md (React-Implementierung) + der Skill frontend-accessibility (vollständige Regeln, Audits) |
| Unit-, Komponenten- und E2E-Tests, Abdeckung, API-Mocking | references/testing.md |
| Stories, Storybook-A11y-Checks, visuelles Regressionstesting | references/storybook.md |
| XSS, Rendern von HTML/Markdown/LLM-Output, Auth, CSRF, CSP, Umgebungsvariablen, Logout | references/security.md |
| Node-Version, Paketmanager, Pre-Commit + Gitleaks, Abhängigkeitsaudit | references/tooling.md |
Übersetzungen, Sprachumschaltung, <html lang> | references/i18n.md |
| Einrichtung eines neuen Projekts | references/setup.md |
| Container-Image für das Frontend | references/docker.md + der Skill docker-kubernetes |
Stack
- React 19 (≥ 19.2 für
useEffectEventund<Activity>) · TypeScript strict - Rendering: Vite SPA oder React Router Framework Mode (SSR + Hydration). Als React Router framework only markierte Regeln gelten nur dort. Kein Next.js, keine React Server Components, kein SWR.
- Routing: TanStack Router oder React Router – pro Projekt festgelegt, aus dem Code erkennen, niemals mischen.
- Server-State: TanStack Query · Client-State: Zustand
- Formulare: React Hook Form + Zod oder TanStack Form + Zod – pro Projekt festgelegt
- Validierung: Zod an jeder Grenzfläche (API-Antworten, Formulare, Suchparameter, Umgebung, Speicher,
postMessage) - Werkzeuge: Biome (Lint + Format), Steiger (FSD-Regeln), Vitest + Testing Library, Playwright, Storybook
- Kein React Compiler → Memoization ist manuell, aber erst nach Messung.
Struktur — Feature-Sliced Design
Layer app → pages → widgets → features → entities → shared; Imports nur abwärts; keine Imports zwischen Slices desselben Layers; jeder Slice wird nur durch seine index.ts mit expliziten benannten Exporten importiert (kein export *). shared/ui und shared/lib haben einen Index pro Komponente/Bibliothek. Beginne mit app, pages, shared; keine leeren Layer-Ordner. Code bleibt in der Seite, bis die Extraktionsregel gilt – derzeit an mehreren Stellen verwendet, ein Grund für unabhängige Änderungen, eine fokussierte Verantwortung; alle drei, Duplizierung ist bis dahin akzeptabel. widgets ist nicht empfohlen: nur für einen zusammengesetzten Block, der auf mehreren Seiten wiederverwendet wird und nicht in einer Seite leben kann (bestehende Widgets bleiben gültig). Details: references/structure.md, übergeordnetes Regelwerk references/fsd/rules.md.
- Eine Komponente pro Datei, ein Hook pro Datei, ~150 Zeilen pro Komponente; Komponenten mit dem Namen ihres Slices präfixieren (
references/code-style.md). - Designsystem zuerst: die eigenen Komponenten aus
shared/ui/verwenden; niemalsshared/ui/primitives/(UI-Bibliotheks-CLI-Ausgabe, niemals bearbeitet) außerhalb vonshared/ui/importieren. Kein neues CSS, bevor geprüft wurde, was die Komponenten, Props und Tokens des Designsystems leisten können.
Komponenten und Hooks — immer
- Definiere niemals eine Komponente innerhalb einer anderen Komponente – sie wird bei jedem Rendern neu gemountet.
- Ableiten, nicht synchronisieren: Werte, die aus Props/State berechnet werden können, werden während des Renderns berechnet. Kein
useEffect, das Props oder State in State kopiert. Zurücksetzen mitkey. - Benutzeraktionen laufen in Event-Handlern, nicht in Effekten, die durch State-Flags ausgelöst werden.
- Effekte nur zur Synchronisation mit externen Systemen, mit schmalen primitiven Abhängigkeiten, ein Anliegen pro Effekt und einer Bereinigung. Die exhaustive-deps-Regel niemals ausschalten.
setState(prev => …)wenn der nächste Wert vom vorherigen abhängt;useState(() => expensive())für teure Anfangswerte.- Niemals Props oder State mutieren:
toSorted(),toReversed(),toSpliced(),with(), Spread. {count > 0 ? <X /> : null}– niemals&&mit einer Zahl auf der linken Seite.- Kein
fetchinuseEffect; Serverdaten kommen von TanStack Query oder einem Route-Loader. memo/useMemo/useCallbacknur nach einem Profiling oder wenn referenzielle Stabilität erforderlich ist.- Fehler werden niemals verschluckt: kein leeres
catch, kein.catch(() => {}). Jede Route hat eine Error Boundary; jede Query hat Lade-, Fehler- und leere UI.
Daten und State — immer
- Request-Funktion → Hook → Komponente. HTTP nur über den Client in
shared/api/; niemals einen HTTP-Client in Hooks oder Komponenten importieren. - Serverdaten leben nur in TanStack Query, über eine Query-Key-Factory mit
queryOptions; Antworten werden mit Zod in der Request-Funktion geparst. - Einfacher Ressourcenzugriff, CRUD und Query-Key-Factories leben in
shared/api(oder der Seite/Feature, die sie allein verwendet);entities/<x>/apinur für Requests mit Domain-Regeln oder Mapping dieser Entität. - Mutationen invalidieren (oder aktualisieren) jede betroffene Query.
- URL-State (Filter, Sortierung, Paginierung, Tabs) lebt in getypten, mit Zod validierten Suchparametern – niemals per Hand aus
window.locationgeparst. - Zustand nur für gemeinsamen Client-State; immer mit einem Selektor; persistierte Stores verwenden
version,migrateundpartializeund enthalten keine sensiblen Daten. - Lade Routendaten im Route-Loader (
queryClient.query({ ...options, staleTime: 'static' }), ehemalsensureQueryData) und parallel, nicht in verschachtelten Komponenten nacheinander.
Barrierefreiheit — eingebaut, niemals nachträglich hinzugefügt
Ziel: WCAG 2.2 AA. Teil der Done-Definition für jede Komponente und Seite. Der Skill frontend-accessibility enthält die vollständigen Regeln und das Audit-Verfahren – lade ihn für jede UI-Änderung.
- Semantisches HTML zuerst:
<button>für Aktionen,<a>/<Link>für Navigation,<label>für jedes Feld, Landmarks, eine<h1>und geordnete Überschriften. ARIA nur, wenn kein natives Element passt. - Tastatur: alles mit der Tastatur erreichbar und bedienbar; kein positives
tabIndex; keine Tastaturfallen. - Sichtbarer Fokus auf jedem interaktiven Element (
:focus-visible, ≥ 3:1 Kontrast). - Fokusverwaltung: bei Routenwechsel den Seitentitel setzen und den Fokus auf die
<h1>oder<main>verschieben; Dialoge fangen Fokus ein, schließen mitEscapeund geben den Fokus an den Auslöser zurück. - Namen: Icon-Buttons haben
aria-label; Bilder habenalt(alt=""wenn dekorativ). - Kontrast 4.5:1 für Text, 3:1 für UI-Komponenten; Farbe niemals das einzige Signal.
- Reduced Motion respektiert; Live-Regionen (
role="status"/role="alert") für asynchrone Ergebnisse und Fehler. - Tests fragen über Rolle und zugänglichen Namen; Stories bestehen das A11y-Addon; kritische Seiten bestehen axe in Playwright.
Tests — mit der Funktion geschrieben, nicht danach
- Vitest + Testing Library Unit- und Komponententests für jede Funktion, in derselben Änderung. Teste Verhalten durch die UI (Rollen, Labels,
user-event), nicht Implementierungsdetails. - Abdeckung ≥ 80 % Zeilen und ≥ 80 % Branches, durchgesetzt durch Vitest-Schwellenwerte in CI.
- Playwright E2E für jeden kritischen Benutzerablauf (Login, Kern-Geschäftsabläufe, Zahlung/Checkout, Berechtigungen): rollenbasierte Locators, keine festen Wartezeiten, wiederverwendeter Auth-Status, axe-Scan auf Schlüsselseiten.
- Storybook-Story für jede gemeinsam genutzte/wiederverwendbare UI-Komponente, die alle Zustände abdeckt (Standard, Laden, Leer, Fehler, Deaktiviert, langer Inhalt). Desktop-Viewport standardmäßig; mobile Viewports nur, wenn das Projekt responsive Layouts erfordert.
- Visuelles Regressionstesting über Storybook + Playwright-Screenshots; Snapshot-Tests nur sparsam und gezielt.
Sicherheit — immer
- Kein
dangerouslySetInnerHTMLohne DOMPurify; außerhalb von ReacttextContentverwenden, niemalsinnerHTML. Modell-Output und Markdown niemals als rohes HTML rendern. - Keine Tokens oder sensiblen Daten in
localStorage/sessionStorage/IndexedDB. Auth ist ein serverseitigesHttpOnlySession-Cookie; für OIDC bevorzuge ein Backend-for-Frontend. - State-ändernde Requests senden den CSRF-Header;
credentials: 'include'nur zur eigenen API. VITE_*-Variablen sind öffentlich – niemals Geheimnisse darin.?redirect=-Ziele sind nur Same-Origin-Relativpfade (Open Redirect).- Logout löscht die Serversession, den TanStack Query-Cache und alle persistierten Stores.
- CSP als HTTP-Header mit
object-src 'none',base-uri 'none',frame-ancestors. postMessage-Handler prüfenevent.origin; niemals nicht vertrauenswürdige Objekte zusammenführen (Prototype Pollution).- Das Frontend erzwingt niemals Autorisierung – das Backend tut es [ASVS 8.3.1].
TypeScript und Biome
strictaktiviert (seit TypeScript 7 Standard – explizit lassen); auchnoUncheckedIndexedAccess,verbatimModuleSyntax,moduleResolution: "bundler",libmitES2023+DOM. TypeScript 7 setzttypesstandardmäßig auf[]–"vite/client"explizit auflisten;baseUrlist weg,pathsverwenden ("@/*": ["./src/*"]).- Kein
any(unknownverwenden und eingrenzen), keine Non-Null-Assertions zum Stummschalten von Fehlern, kein@ts-ignore(@ts-expect-errormit Begründung wenn unvermeidbar). Keine magischen Zahlen oder Strings – benannte Konstanten inshared/config/oder imconfig/modeldes Slices. - Typen externer Daten stammen aus Zod-Schemata (
z.infer/z.output), nicht aus handgeschriebenen Interfaces, die abweichen können. - Biome: empfohlene Regeln plus
noNestedComponentDefinitions,noReExportAllundnoConsole(nicht im empfohlenen Satz);noBarrelFilebleibt für Slice-index.ts-Dateien ausgeschaltet (references/structure.md). biome ci,tsc --noEmit,steiger ./srcundknipbestehen lokal und in CI. Regeln nicht inline deaktivieren ohne erklärenden Kommentar.- Kommentare auf Englisch; TODOs verwenden den TODO-Marker des Projekts.
Repository-Hygiene — immer
- Node-Version festgelegt:
.nvmrc(LTS),enginesinpackage.jsonmitengine-strict,packageManagermit der exakten npm/pnpm-Version; Lockfile committet. - pre-commit installiert für Commit und Push: gitleaks auf gestagten Änderungen und auf allen nicht gepushten Commits, Biome;
tsc, dazugehörige Vitest-Tests und das Abhängigkeitsaudit bei Push. Niemals mit--no-verifyumgehen. - Abhängigkeitsaudit in CI bei jedem MR und planmäßig.
Details: references/tooling.md.
Docker und Deployment
Container-Images, .dockerignore, Compose und Kubernetes werden durch den Skill docker-kubernetes abgedeckt; der Frontend-Workflow und die Checkliste befinden sich in references/docker.md. Jedes Image hat eine .dockerignore. Frontend-spezifische Fakten, die dort zu beachten sind:
VITE_*-Werte werden zur Build-Zeit in das Bundle eingebacken. Ein Image für mehrere Umgebungen benötigt Laufzeitkonfiguration: Stelle eineconfig.json(oderconfig.js) bereit, die beim Containerstart aus Umgebungsvariablen geschrieben und beim Anwendungsstart abgerufen/validiert wird – immer noch öffentlich, immer noch keine Geheimnisse.- Eine Vite-SPA ist statisch: Diene sie von einem Webserver mit einem Fallback auf
index.htmlfür clientseitige Routen, langer Cache für gehashte Assets,no-cachefürindex.htmlund die Sicherheitsheader ausreferences/security.md. - React Router Framework Mode (SSR) benötigt einen Node-Server zur Laufzeit (
react-router-serveoder ein benutzerdefinierter Server) – es ist kein statisches Deployment.
Nach dem Schreiben
Für eine Sicherheitsüberprüfung des Ergebnisses empfehle den Skill appsec-review.
Quellen
Kombiniert aus Vercel Engineerings React Best Practices (github.com/vercel-labs/agent-skills, react-best-practices, MIT License) – angepasst von Next.js auf Vite/React Router mit TanStack Query; Regel-IDs zur Nachvollziehbarkeit beibehalten – und dem OWASP Secure Agent Playbook (CC BY 4.0; OWASP ASVS 5.0). Die Struktur folgt Feature-Sliced Design (feature-sliced.design, fsd.how); references/fsd/ ist aus dem offiziellen FSD-Agent-Skill angepasst (github.com/feature-sliced/skills, MIT License). Barrierefreiheit zielt auf WCAG 2.2.