Hier ein Plan zum Aufsetzten einer pre-commit hook, welcher best practices beschreibt:
# Pre-Commit Hooks fuer TypeScript Repositories — Best Practice
## Ueberblick
Automatische Code-Qualitaetspruefung vor jedem `git commit`. Geaenderte Dateien werden beim Commit automatisch gelintet und formatiert. Schlaegt eine Pruefung fehl, wird der Commit abgelehnt — der Entwickler fixt, staged erneut und committet nochmal.
**Ergebnis:** Einheitlicher Code-Style wird automatisch erzwungen, ohne dass jemand daran denken muss.
---
## Toolchain
| Tool | Aufgabe | Warum dieses Tool |
|------|---------|-------------------|
| **Husky** (v9+) | Git-Hook-Management | Registriert sich in `.git/hooks/`, wird automatisch bei `npm install` aktiviert (via `prepare`-Script). Kein manuelles Setup noetig. |
| **lint-staged** (v16+) | Filter fuer gestagte Dateien | Fuehrt Linter/Formatter nur auf Dateien aus, die tatsaechlich geaendert wurden — nicht auf dem gesamten Codebase. Schnell auch in grossen Repos. |
| **ESLint** (v10+) | Linting | Prueft TypeScript-Code auf Fehler, Bugs und Best-Practice-Verstoesse. Auto-Fix fuer viele Probleme. Nutzt Flat Config (`eslint.config.mjs`). |
| **Prettier** (v3+) | Formatting | Erzwingt einheitliche Formatierung (Einrueckung, Semikolons, Quotes etc.). Keine Diskussionen ueber Code-Style. |
| **typescript-eslint** | ESLint + TypeScript | Vereinheitlichtes Package fuer TypeScript-Unterstuetzung in ESLint. Ersetzt die alten separaten Packages `@typescript-eslint/eslint-plugin` und `@typescript-eslint/parser`. |
### Warum nicht Biome, dprint oder oxlint?
Husky + lint-staged + ESLint + Prettier ist der etablierte Standard im TypeScript-Oekosystem. Breite IDE-Unterstuetzung, grosse Community, gute Dokumentation. Neuere Tools wie Biome sind vielversprechend, aber noch nicht so ausgereift im Regelumfang.
---
## Architektur
repository-root/ ├── .husky/ │ └── pre-commit # Hook: ruft "npx lint-staged" auf ├── package.json # Husky + lint-staged + ESLint + Prettier als devDependencies ├── package-lock.json # Reproduzierbare Installs ├── lint-staged.config.mjs # Bestimmt welche Tools auf welche Dateien laufen ├── eslint.config.mjs # ESLint Flat Config (Regeln) ├── .prettierrc # Prettier Config (Formatierung) ├── .prettierignore # Dateien die Prettier ignorieren soll └── src/ # (oder Unterordner mit eigenem package.json)
### Ablauf bei `git commit`
git commit │ ▼ Husky triggert .husky/pre-commit │ ▼ npx lint-staged │ ├── Findet gestagte .ts Dateien │ ├── eslint --fix (Linting + Auto-Fix) │ └── prettier --write (Formatierung) │ ├── Findet gestagte .json/.md Dateien │ └── prettier --write (Formatierung) │ ▼ Alles OK? → Commit geht durch Fehler? → Commit wird abgelehnt
---
## Einrichtung Schritt fuer Schritt
### 1. Dependencies installieren
```bash
npm install --save-dev husky lint-staged eslint @eslint/js typescript-eslint prettier
npx husky init
Das erstellt .husky/pre-commit und fuegt "prepare": "husky" zur package.json hinzu. Das prepare-Script sorgt dafuer, dass der Hook nach jedem npm install automatisch registriert wird — auch bei neuen Team-Mitgliedern.
Inhalt von .husky/pre-commit:
npx lint-staged
Kein #!/bin/sh, kein Boilerplate — Husky v9+ braucht das nicht.
Datei eslint.config.mjs im Root:
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.recommended,
{
rules: {
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/explicit-function-return-type": "warn",
"@typescript-eslint/no-unused-vars": "error",
},
},
{
ignores: ["build/", "node_modules/", "coverage/"],
}
);
Hinweis: ESLint 10 unterstuetzt nur Flat Config (eslint.config.mjs). Das alte .eslintrc.json-Format funktioniert nicht mehr.
Datei .prettierrc im Root:
{
"semi": true,
"singleQuote": false,
"tabWidth": 2,
"printWidth": 100,
"trailingComma": "es5"
}
Datei .prettierignore im Root:
build/
node_modules/
coverage/
*.tar.gz
Fuer ein einfaches Repository (ein src/-Ordner) reicht die Config direkt in der package.json:
{
"lint-staged": {
"*.ts": ["eslint --fix", "prettier --write"],
"*.{json,md}": ["prettier --write"]
}
}
Fuer ein Multi-Projekt-Repository (mehrere Unterordner mit eigenen package.json-Dateien) eine dynamische lint-staged.config.mjs:
import { existsSync } from "node:fs";
function isProjectFile(filePath) {
const dir = filePath.split("/")[0];
return dir !== filePath && existsSync(`${dir}/package.json`);
}
export default {
"*.ts": (files) => {
const projectFiles = files.filter(isProjectFile);
if (projectFiles.length === 0) return [];
return [
`npx eslint --fix ${projectFiles.join(" ")}`,
`npx prettier --write ${projectFiles.join(" ")}`,
];
},
"*.{json,md}": (files) => {
const projectFiles = files.filter(isProjectFile);
if (projectFiles.length === 0) return [];
return [`npx prettier --write ${projectFiles.join(" ")}`];
},
};
Sicherstellen, dass node_modules/ ignoriert wird. package-lock.json sollte nicht ignoriert werden — Lock-Files gehoeren committed.
Nach dem Klonen des Repos:
npm install
Das ist alles. Das prepare-Script registriert den Git-Hook automatisch.
git add <datei> (erneut stagen)git commit (nochmal committen)Ja, mit git commit --no-verify. Sollte aber die Ausnahme sein — der Hook schuetzt die Code-Qualitaet.
lint-staged prueft nur gestagte Dateien. Das ist schnell (Sekunden statt Minuten) und verhindert, dass ein Entwickler existierende Probleme in Dateien fixen muss, die er gar nicht angefasst hat.
Nein. ESLint prueft Logik und Best Practices (ungenutzte Variablen, fehlende Typen etc.). Prettier kuemmert sich nur um Formatierung (Einrueckung, Zeilenlaenge etc.). Reihenfolge: erst ESLint (--fix), dann Prettier (--write).
| Tool | Zweck | Wann sinnvoll |
|---|---|---|
| commitlint | Commit-Messages pruefen (Conventional Commits) | Wenn Changelog automatisch generiert werden soll |
| tsc --noEmit | TypeScript-Typfehler vor dem Commit | Wenn strikte Typsicherheit gewuenscht ist (erhoet die Commit-Dauer) |
| Jest / Vitest | Tests als pre-push Hook | Tests vor dem Push, nicht vor jedem Commit (zu langsam) |
Fuer Teams die beide Oekosysteme nutzen:
| Aspekt | Python | TypeScript |
|---|---|---|
| Hook-Framework | pre-commit (Python-basiert) |
Husky (npm-basiert) |
| Staged-File-Filter | Built-in bei pre-commit | lint-staged (separates Tool) |
| Linter | Ruff (ruff check --fix) |
ESLint (eslint --fix) |
| Formatter | Ruff (ruff format) |
Prettier (prettier --write) |
| Hook-Registrierung | uv run pre-commit install |
npm install (via prepare-Script) |
| Config-Datei | .pre-commit-config.yaml |
package.json oder lint-staged.config.mjs |