Coding Standards
Diese Dokumentation beschreibt die Coding Standards für die Smolitux-UI-Bibliothek.
Allgemeine Richtlinien
- Lesbarkeit: Schreiben Sie lesbaren und selbsterklärenden Code.
- Einfachheit: Halten Sie den Code so einfach wie möglich.
- Konsistenz: Folgen Sie konsistenten Mustern und Konventionen.
- Modularität: Schreiben Sie modularen und wiederverwendbaren Code.
- Testbarkeit: Schreiben Sie testbaren Code.
Formatierung
- Einrückung: Verwenden Sie 2 Leerzeichen für die Einrückung.
- Zeilenumbrüche: Begrenzen Sie Zeilen auf 100 Zeichen.
- Klammern: Öffnende Klammern stehen am Ende der Zeile, schließende Klammern stehen in einer eigenen Zeile.
- Leerzeichen: Verwenden Sie Leerzeichen um Operatoren und nach Kommas.
- Semikolons: Verwenden Sie Semikolons am Ende jeder Anweisung.
// Gut
function example(param1, param2) {
const result = param1 + param2;
return result;
}
// Schlecht
function example ( param1,param2 ){
const result=param1+param2
return result
}
Benennung
- Variablen und Funktionen: Verwenden Sie camelCase für Variablen und Funktionen.
- Komponenten: Verwenden Sie PascalCase für Komponenten.
- Konstanten: Verwenden Sie UPPER_SNAKE_CASE für Konstanten.
- Typen und Interfaces: Verwenden Sie PascalCase für Typen und Interfaces.
- Dateien: Verwenden Sie PascalCase für Komponentendateien und camelCase für andere Dateien.
// Variablen und Funktionen
const userName = 'John';
function calculateTotal() { ... }
// Komponenten
const UserProfile = () => { ... };
// Konstanten
const MAX_ITEMS = 10;
// Typen und Interfaces
interface UserData { ... }
type ButtonVariant = 'primary' | 'secondary';
TypeScript
- Typen: Definieren Sie explizite Typen für alle Variablen, Parameter und Rückgabewerte.
- Interfaces: Verwenden Sie Interfaces für Objekte und Props.
- Generics: Verwenden Sie Generics für wiederverwendbare Typen.
- Enums: Vermeiden Sie Enums, verwenden Sie stattdessen Union Types.
- any: Vermeiden Sie den Typ
any
, verwenden Sie stattdessenunknown
oder spezifische Typen.
// Gut
interface User {
id: string;
name: string;
age: number;
}
function getUser(id: string): User | null {
// ...
}
// Schlecht
function getUser(id): any {
// ...
}
React
- Funktionale Komponenten: Verwenden Sie funktionale Komponenten mit Hooks.
- Props: Definieren Sie Props-Interfaces für alle Komponenten.
- Hooks: Folgen Sie den Regeln für Hooks.
- Memoization: Verwenden Sie
useMemo
unduseCallback
für teure Berechnungen und Callbacks. - Rendering: Vermeiden Sie unnötige Renderings.
// Gut
interface ButtonProps {
label: string;
onClick: () => void;
disabled?: boolean;
}
const Button: React.FC<ButtonProps> = ({ label, onClick, disabled = false }) => {
const handleClick = useCallback(() => {
onClick();
}, [onClick]);
return (
<button onClick={handleClick} disabled={disabled}>
{label}
</button>
);
};
// Schlecht
const Button = (props) => {
return (
<button onClick={props.onClick} disabled={props.disabled}>
{props.label}
</button>
);
};
Kommentare
- JSDoc: Verwenden Sie JSDoc-Kommentare für Komponenten, Funktionen und Typen.
- Inline-Kommentare: Verwenden Sie Inline-Kommentare für komplexe Logik.
- TODO-Kommentare: Markieren Sie unvollständigen Code mit TODO-Kommentaren.
- Vermeiden: Vermeiden Sie offensichtliche Kommentare.
- Aktualisieren: Halten Sie Kommentare aktuell.
/**
* Button-Komponente für Aktionen.
* @param {ButtonProps} props - Die Props für die Button-Komponente.
* @returns {JSX.Element} Die Button-Komponente.
*/
const Button: React.FC<ButtonProps> = ({ label, onClick, disabled = false }) => {
// Komplexe Logik, die einen Kommentar benötigt
const handleClick = useCallback(() => {
// TODO: Implementieren Sie Tracking
onClick();
}, [onClick]);
return (
<button onClick={handleClick} disabled={disabled}>
{label}
</button>
);
};
Fehlerbehandlung
- Try-Catch: Verwenden Sie try-catch-Blöcke für fehleranfällige Operationen.
- Error-Boundaries: Verwenden Sie Error-Boundaries für React-Komponenten.
- Fehlertypen: Definieren Sie spezifische Fehlertypen.
- Logging: Loggen Sie Fehler mit ausreichend Kontext.
- Benutzerfreundlichkeit: Zeigen Sie benutzerfreundliche Fehlermeldungen an.
try {
const data = await fetchData();
processData(data);
} catch (error) {
console.error('Failed to fetch data:', error);
showErrorMessage('Failed to load data. Please try again later.');
}
Imports
- Gruppierung: Gruppieren Sie Imports nach Typ.
- Sortierung: Sortieren Sie Imports alphabetisch innerhalb jeder Gruppe.
- Aliase: Vermeiden Sie Import-Aliase, es sei denn, sie sind notwendig.
- Pfade: Verwenden Sie relative Pfade für lokale Imports und absolute Pfade für Pakete.
- Destrukturierung: Verwenden Sie Destrukturierung für spezifische Imports.
// Externe Pakete
import React, { useState, useEffect, useCallback } from 'react';
import { useRouter } from 'next/router';
// Interne Module
import { Button } from '@smolitux/utils/src/components/patterns';
import { Box, Flex, Text } from '@smolitux/utils/src/components/primitives';
// Lokale Imports
import { formatDate } from '../../utils/formatters';
import { validateInput } from '../../utils/validators';
Tests
- Testabdeckung: Streben Sie eine hohe Testabdeckung an.
- Isolation: Testen Sie Komponenten isoliert.
- Mocking: Mocken Sie externe Abhängigkeiten.
- Assertions: Verwenden Sie aussagekräftige Assertions.
- Beschreibungen: Schreiben Sie klare Test-Beschreibungen.
describe('Button', () => {
it('renders with the correct label', () => {
render(<Button label="Click me" onClick={() => {}} />);
expect(screen.getByText('Click me')).toBeInTheDocument();
});
it('calls onClick when clicked', () => {
const onClick = jest.fn();
render(<Button label="Click me" onClick={onClick} />);
fireEvent.click(screen.getByText('Click me'));
expect(onClick).toHaveBeenCalledTimes(1);
});
it('is disabled when disabled prop is true', () => {
render(<Button label="Click me" onClick={() => {}} disabled />);
expect(screen.getByText('Click me')).toBeDisabled();
});
});
Performance
- Memoization: Verwenden Sie
useMemo
unduseCallback
für teure Berechnungen und Callbacks. - Virtualisierung: Verwenden Sie Virtualisierung für lange Listen.
- Code-Splitting: Verwenden Sie Code-Splitting für große Komponenten.
- Lazy-Loading: Verwenden Sie Lazy-Loading für Komponenten, die nicht sofort benötigt werden.
- Optimierung: Optimieren Sie Renderings mit
React.memo
undshouldComponentUpdate
.
// Memoization
const expensiveCalculation = useMemo(() => {
return computeExpensiveValue(a, b);
}, [a, b]);
// Virtualisierung
import { VirtualList } from 'react-virtualized';
const List = ({ items }) => {
return (
<VirtualList
width={500}
height={500}
rowCount={items.length}
rowHeight={50}
rowRenderer={({ index, key, style }) => (
<div key={key} style={style}>
{items[index]}
</div>
)}
/>
);
};
// Code-Splitting
const LazyComponent = React.lazy(() => import('./LazyComponent'));
const App = () => {
return (
<React.Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</React.Suspense>
);
};
Sicherheit
- XSS: Vermeiden Sie XSS-Angriffe durch Escaping von Benutzereingaben.
- CSRF: Schützen Sie vor CSRF-Angriffen.
- Abhängigkeiten: Halten Sie Abhängigkeiten aktuell.
- Secrets: Speichern Sie keine Secrets im Client-Code.
- Validierung: Validieren Sie Benutzereingaben sowohl im Client als auch im Server.
// Gut
const UserContent = ({ content }) => {
return <div>{content}</div>; // React escaped automatisch
};
// Schlecht
const UserContent = ({ content }) => {
return <div dangerouslySetInnerHTML={{ __html: content }} />; // Gefährlich!
};
Barrierefreiheit
- Semantik: Verwenden Sie semantische HTML-Elemente.
- ARIA: Verwenden Sie ARIA-Attribute, wenn semantisches HTML nicht ausreicht.
- Keyboard: Stellen Sie sicher, dass alle Interaktionen mit der Tastatur möglich sind.
- Kontrast: Stellen Sie sicher, dass der Kontrast ausreichend ist.
- Screenreader: Testen Sie mit Screenreadern.
// Gut
<button onClick={handleClick} aria-label="Close dialog">
<span aria-hidden="true">×</span>
</button>
// Schlecht
<div onClick={handleClick}>×</div>
Internationalisierung
- Strings: Externalisieren Sie alle Strings für Übersetzungen.
- Formatierung: Verwenden Sie lokalisierte Formatierung für Datum, Zeit und Zahlen.
- Richtung: Unterstützen Sie bidirektionalen Text.
- Pluralisierung: Verwenden Sie Pluralisierungsregeln.
- Kontextualisierung: Geben Sie Kontext für Übersetzungen an.
// Gut
import { useTranslation } from 'react-i18next';
const Welcome = () => {
const { t } = useTranslation();
return <h1>{t('welcome.title')}</h1>;
};
// Schlecht
const Welcome = () => {
return <h1>Welcome to our app</h1>;
};
Versionierung
- Semantic Versioning: Folgen Sie Semantic Versioning (MAJOR.MINOR.PATCH).
- Changelog: Führen Sie ein Changelog.
- Breaking Changes: Dokumentieren Sie Breaking Changes.
- Deprecation: Markieren Sie veraltete Funktionen als veraltet.
- Migration: Stellen Sie Migrationsleitfäden bereit.
// Veraltet
/**
* @deprecated Verwenden Sie stattdessen NewComponent.
*/
export const OldComponent = () => {
return <div>Old Component</div>;
};
Dokumentation
- README: Stellen Sie eine README-Datei bereit.
- JSDoc: Dokumentieren Sie Komponenten, Funktionen und Typen mit JSDoc.
- Beispiele: Geben Sie Beispiele für die Verwendung.
- Storybook: Erstellen Sie Storybook-Geschichten für Komponenten.
- API-Referenz: Stellen Sie eine API-Referenz bereit.
/**
* Button-Komponente für Aktionen.
*
* @example
* ```tsx
* <Button label="Click me" onClick={() => console.log('Clicked')} />
* ```
*
* @param {ButtonProps} props - Die Props für die Button-Komponente.
* @returns {JSX.Element} Die Button-Komponente.
*/
export const Button: React.FC<ButtonProps> = ({ label, onClick, disabled = false }) => {
// ...
};