Senior Frontend
Frontend-Entwicklungsmuster, Leistungsoptimierung und Automatisierungswerkzeuge für React/Next.js-Anwendungen.
Inhaltsverzeichnis
- Projektgerüst
- Komponentenerzeugung
- Bundle-Analyse
- React-Muster
- Next.js-Optimierung
- Barrierefreiheit und Testen
Projektgerüst
Erzeugen Sie ein neues Next.js- oder React-Projekt mit TypeScript, Tailwind CSS und Konfigurationen nach Best Practices.
Arbeitsablauf: Neues Frontend-Projekt erstellen
-
Führen Sie den Gerüstbauer mit Ihrem Projektnamen und der Vorlage aus:
python scripts/frontend_scaffolder.py my-app --template nextjs -
Fügen Sie optionale Funktionen hinzu (auth, api, forms, testing, storybook):
python scripts/frontend_scaffolder.py dashboard --template nextjs --features auth,api -
Navigieren Sie zum Projekt und installieren Sie Abhängigkeiten:
cd my-app && npm install -
Starten Sie den Entwicklungsserver:
npm run dev
Optionen des Gerüstbauers
| Option | Beschreibung |
|---|---|
--template nextjs | Next.js 14+ mit App Router und Server-Komponenten |
--template react | React + Vite mit TypeScript |
--features auth | NextAuth.js-Authentifizierung hinzufügen |
--features api | React Query + API-Client hinzufügen |
--features forms | React Hook Form + Zod-Validierung hinzufügen |
--features testing | Vitest + Testing Library hinzufügen |
--dry-run | Dateien anzeigen, ohne sie zu erstellen |
Generierte Struktur (Next.js)
my-app/
├── app/
│ ├── layout.tsx # Root-Layout mit Schriftarten
│ ├── page.tsx # Startseite
│ ├── globals.css # Tailwind + CSS-Variablen
│ └── api/health/route.ts
├── components/
│ ├── ui/ # Button, Input, Card
│ └── layout/ # Header, Footer, Sidebar
├── hooks/ # useDebounce, useLocalStorage
├── lib/ # utils (cn), Konstanten
├── types/ # TypeScript-Schnittstellen
├── tailwind.config.ts
├── next.config.js
└── package.json
Komponentenerzeugung
Generieren Sie React-Komponenten mit TypeScript, Tests und Storybook-Stories.
Arbeitsablauf: Eine neue Komponente erstellen
-
Generieren Sie eine Client-Komponente:
python scripts/component_generator.py Button --dir src/components/ui -
Generieren Sie eine Server-Komponente:
python scripts/component_generator.py ProductCard --type server -
Generieren Sie mit Test- und Story-Dateien:
python scripts/component_generator.py UserProfile --with-test --with-story -
Generieren Sie einen benutzerdefinierten Hook:
python scripts/component_generator.py FormValidation --type hook
Optionen des Generators
| Option | Beschreibung |
|---|---|
--type client | Client-Komponente mit 'use client' (Standard) |
--type server | Asynchrone Server-Komponente |
--type hook | Benutzerdefinierter React-Hook |
--with-test | Testdatei einschließen |
--with-story | Storybook-Story einschließen |
--flat | Im Ausgabeverzeichnis ohne Unterverzeichnis erstellen |
--dry-run | Vorschau ohne Dateierstellung |
Beispiel einer generierten Komponente
'use client';
import { useState } from 'react';
import { cn } from '@/lib/utils';
interface ButtonProps {
className?: string;
children?: React.ReactNode;
}
export function Button({ className, children }: ButtonProps) {
return (
<div className={cn('', className)}>
{children}
</div>
);
}
Bundle-Analyse
Analysieren Sie package.json und die Projektstruktur auf Optimierungsmöglichkeiten der Bundlegröße.
Arbeitsablauf: Bundlegröße optimieren
-
Führen Sie den Analysator für Ihr Projekt aus:
python scripts/bundle_analyzer.py /path/to/project -
Überprüfen Sie den Gesundheitswert und die Probleme:
Bundle-Gesundheitswert: 75/100 (C) SCHWERE ABHÄNGIGKEITEN: moment (290KB) Alternative: date-fns (12KB) oder dayjs (2KB) lodash (71KB) Alternative: lodash-es mit Tree-Shaking -
Wenden Sie die empfohlenen Korrekturen an, indem Sie schwere Abhängigkeiten ersetzen.
-
Führen Sie den Analysator erneut im ausführlichen Modus aus, um Importmuster zu überprüfen:
python scripts/bundle_analyzer.py . --verbose
Interpretation des Bundle-Scores
| Punktzahl | Note | Aktion |
|---|---|---|
| 90-100 | A | Bundle ist gut optimiert |
| 80-89 | B | Kleine Optimierungen verfügbar |
| 70-79 | C | Schwere Abhängigkeiten ersetzen |
| 60-69 | D | Mehrere Probleme erfordern Aufmerksamkeit |
| 0-59 | F | Kritische Probleme mit der Bundlegröße |
Erkannte schwere Abhängigkeiten
Der Analysator identifiziert diese häufigen schweren Pakete:
| Paket | Größe | Alternative |
|---|---|---|
| moment | 290KB | date-fns (12KB) oder dayjs (2KB) |
| lodash | 71KB | lodash-es mit Tree-Shaking |
| axios | 14KB | Native fetch oder ky (3KB) |
| jquery | 87KB | Native DOM-APIs |
| @mui/material | Groß | shadcn/ui oder Radix UI |
React-Muster
Referenz: references/react_patterns.md
Compound-Komponenten
Teilen Sie den Zustand zwischen verwandten Komponenten:
const Tabs = ({ children }) => {
const [active, setActive] = useState(0);
return (
<TabsContext.Provider value={{ active, setActive }}>
{children}
</TabsContext.Provider>
);
};
Tabs.List = TabList;
Tabs.Panel = TabPanel;
// Verwendung
<Tabs>
<Tabs.List>
<Tabs.Tab>Eins</Tabs.Tab>
<Tabs.Tab>Zwei</Tabs.Tab>
</Tabs.List>
<Tabs.Panel>Inhalt 1</Tabs.Panel>
<Tabs.Panel>Inhalt 2</Tabs.Panel>
</Tabs>
Benutzerdefinierte Hooks
Extraktion wiederverwendbarer Logik:
function useDebounce<T>(value: T, delay = 500): T {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timer = setTimeout(() => setDebouncedValue(value), delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debouncedValue;
}
// Verwendung
const debouncedSearch = useDebounce(searchTerm, 300);
Render-Props
Teilen Sie Rendering-Logik:
function DataFetcher({ url, render }) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url).then(r => r.json()).then(setData).finally(() => setLoading(false));
}, [url]);
return render({ data, loading });
}
// Verwendung
<DataFetcher
url="/api/users"
render={({ data, loading }) =>
loading ? <Spinner /> : <UserList users={data} />
}
/>
Next.js-Optimierung
Referenz: references/nextjs_optimization_guide.md
Server- vs. Client-Komponenten
Verwenden Sie standardmäßig Server-Komponenten. Fügen Sie 'use client' nur hinzu, wenn Sie Folgendes benötigen:
- Ereignishandler (onClick, onChange)
- Zustand (useState, useReducer)
- Effekte (useEffect)
- Browser-APIs
// Server-Komponente (Standard) - kein 'use client'
async function ProductPage({ params }) {
const product = await getProduct(params.id); // Server-seitiger Fetch
return (
<div>
<h1>{product.name}</h1>
<AddToCartButton productId={product.id} /> {/* Client-Komponente */}
</div>
);
}
// Client-Komponente
'use client';
function AddToCartButton({ productId }) {
const [adding, setAdding] = useState(false);
return <button onClick={() => addToCart(productId)}>Hinzufügen</button>;
}
Bildoptimierung
import Image from 'next/image';
// Above the fold - sofort laden
<Image
src="/hero.jpg"
alt="Held"
width={1200}
height={600}
priority
/>
// Responsives Bild mit fill
<div className="relative aspect-video">
<Image
src="/product.jpg"
alt="Produkt"
fill
sizes="(max-width: 768px) 100vw, 50vw"
className="object-cover"
/>
</div>
Datenabruf-Muster
// Paralleler Abruf
async function Dashboard() {
const [user, stats] = await Promise.all([
getUser(),
getStats()
]);
return <div>...</div>;
}
// Streaming mit Suspense
async function ProductPage({ params }) {
return (
<div>
<ProductDetails id={params.id} />
<Suspense fallback={<ReviewsSkeleton />}>
<Reviews productId={params.id} />
</Suspense>
</div>
);
}
Barrierefreiheit und Testen
Referenz: references/frontend_best_practices.md
Checkliste für Barrierefreiheit
- Semantisches HTML: Verwenden Sie geeignete Elemente (
<button>,<nav>,<main>) - Tastaturnavigation: Alle interaktiven Elemente fokussierbar
- ARIA-Labels: Labels für Symbole und komplexe Widgets bereitstellen
- Farbkontrast: Mindestens 4,5:1 für normalen Text
- Fokus-Indikatoren: Sichtbare Fokus-Zustände
// Barrierefreier Button
<button
type="button"
aria-label="Dialog schließen"
onClick={onClose}
className="focus-visible:ring-2 focus-visible:ring-blue-500"
>
<XIcon aria-hidden="true" />
</button>
// Skip-Link für Tastaturnutzer
<a href="#main-content" className="sr-only focus:not-sr-only">
Zum Hauptinhalt springen
</a>
Teststrategie
// Komponententest mit React Testing Library
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
test('Button löst bei Klick Aktion aus', async () => {
const onClick = vi.fn();
render(<Button onClick={onClick}>Klick mich</Button>);
await userEvent.click(screen.getByRole('button'));
expect(onClick).toHaveBeenCalledTimes(1);
});
// Barrierefreiheit testen
test('Dialog ist barrierefrei', async () => {
render(<Dialog open={true} title="Bestätigen" />);
expect(screen.getByRole('dialog')).toBeInTheDocument();
expect(screen.getByRole('dialog')).toHaveAttribute('aria-labelledby');
});
Kurzreferenz
Allgemeine Next.js-Konfiguration
// next.config.js
const nextConfig = {
images: {
remotePatterns: [{ protocol: 'https', hostname: 'cdn.example.com' }],
formats: ['image/avif', 'image/webp'],
},
experimental: {
optimizePackageImports: ['lucide-react', '@heroicons/react'],
},
};
Tailwind CSS-Hilfsmittel
// Bedingte Klassen mit cn()
import { cn } from '@/lib/utils';
<button className={cn(
'px-4 py-2 rounded',
variant === 'primary' && 'bg-blue-500 text-white',
disabled && 'opacity-50 cursor-not-allowed'
)} />
TypeScript-Muster
// Props mit children
interface CardProps {
className?: string;
children: React.ReactNode;
}
// Generische Komponente
interface ListProps<T> {
items: T[];
renderItem: (item: T) => React.ReactNode;
}
function List<T>({ items, renderItem }: ListProps<T>) {
return <ul>{items.map(renderItem)}</ul>;
}
Ressourcen
- React-Muster:
references/react_patterns.md - Next.js-Optimierung:
references/nextjs_optimization_guide.md - Best Practices:
references/frontend_best_practices.md - Forcing-Questions-Bibliothek (Matt Pocock grill):
references/forcing_questions.md - Kompositionskarte (welcher Spezialist für welchen Fork):
references/composition_map.md
Annahmen und überprüfbare Erfolgskriterien (Karpathy-Disziplin)
Bevor dieser Skill eine Komponente erstellt, ein Framework empfiehlt oder ein Bundle prüft, MÜSSEN die folgenden vier Annahmen offengelegt werden.
- Primäres Benutzergerät + Netzwerk — mobile-4G, Desktop-Fiber, Low-End-Android oder Unternehmensnetzwerk. Treibt jede Leistungsentscheidung.
- LCP-Ziel in Millisekunden — eine einzelne Zahl, nicht „schnell“. Treibt das Bundle-Budget und die Rendering-Wahl.
- SEO-abhängig vs. authentifizierungspflichtig — treibt das Rendering (SSR/SSG/RSC vs. SPA).
- WCAG-Ziel + benannter a11y-Verantwortlicher — AA, AAA oder Best-Effort. Treibt das a11y-Investment und die CI-Gates.
Überprüfbare Erfolgskriterien (Karpathy #4) — jede Empfehlung muss Folgendes enthalten:
- Core Web Vitals-Ziele (LCP, INP, CLS) bei p75 auf dem primären Gerät
- Ein JS-Bundle-Budget pro Route in KB-gzip
- Ein Lighthouse a11y-Mindestwert + Leistungs-Mindestwert
Wenn eines dieser drei nicht angegeben ist, ist die Empfehlung unvollständig – kehren Sie zu Q2 der Forcing-Questions-Bibliothek zurück.
Das Werkzeug scripts/frontend_decision_engine.py kodiert diese Prüfungen: Es lehnt es ab, ein Profil ohne die vier Annahme-Eingaben zu empfehlen, und gibt die überprüfbaren Schwellenwerte für das passende Profil aus.
Anpassungsprofile
Vier integrierte Profile in profiles/ kalibrieren jede Empfehlung:
| Profil | Wann auswählen | LCP-Ziel (mobile-4G p75) | Bundle-Budget |
|---|---|---|---|
next-app-router | SaaS-kundenorientiert, SEO + dynamisch, RSC-first | 2000ms | 150 KB-gzip / Route |
remix-or-sveltekit | Mobile-4G primär, Low-JS-first, progressive Verbesserung | 1500ms | 80 KB-gzip / Route |
vite-spa | Authentifizierungspflichtige App, Desktop/Unternehmen primär | 2500ms | 200 KB Init + 80 KB / Route |
astro-or-static | Marketing / Docs / Blog, nahezu null Schreibvorgänge, SEO-kritisch | 1200ms | 30 KB JS / Seite |
Wählen Sie ein Profil aus mit:
python scripts/frontend_decision_engine.py \
--primary-device mobile-4g --lcp-target-ms 2000 \
--seo-dependent true --auth-walled false --team-size 5
Das Tool gibt das am besten passende Profil, den Kompromiss des Zweitplatzierten (wenn innerhalb von 15 %), die Technologieauswahl, die zu vermeidenden Anti-Patterns für dieses Profil und die erforderlichen CI-Gates zurück.
Um ein benutzerdefiniertes Profil hinzuzufügen (z. B. die Standards Ihres Unternehmens für interne Tools): kopieren Sie profiles/vite-spa.json nach profiles/<ihr-unternehmen>.json und passen Sie constraints + success_thresholds an.
Kompositionskarte
Dieser Skill setzt NICHT den Umfang neu um, der von den POWERFUL-Stufen-Spezialisten abgedeckt wird. Er verzweigt (forkt) in diese hinein. Siehe references/composition_map.md für die vollständige Routing-Tabelle. Wichtige Forks:
| Betreff | Fork in |
|---|---|
| WCAG-Audit, Kontrast, Screenreader | engineering-team/skills/a11y-audit/ |
| Bundle-Profiling + Laufzeitleistung | engineering/skills/performance-profiler/ |
| Kinematografische / Scroll-Storytelling-Landingpage | engineering-team/skills/epic-design/ |
| Apple HIG (iOS / macOS / visionOS) | product-team/skills/apple-hig-expert/ |
| Pre-Commit-Karpathy-Review | engineering/karpathy-coder/ |
| Pre-Flight-Architektur-Grill | engineering/grill-me/ |
Der cs-frontend-engineer-Agent orchestriert diese Forks über context: fork. Rufen Sie ihn von einem anderen Agenten auf mit Agent({subagent_type: "cs-frontend-engineer", prompt: "..."}) oder
…
[gekürzt zur Übersetzung]