🐕 Husky + commitlint + lint-staged

Guide complet pour Next.js — avec npm et pnpm — basé sur la documentation officielle

Ce qu'on installe et pourquoi

Trois outils qui travaillent ensemble pour garder un code propre et des commits lisibles.

git commit Husky déclenche lint-staged + commitlint commit validé ✓
🐕 Husky
Écoute les événements Git (pre-commit, commit-msg) et exécute des scripts automatiquement. C'est le chef d'orchestre.
⚡ lint-staged
Lance ESLint + Prettier uniquement sur les fichiers modifiés. Beaucoup plus rapide que de relire tout le projet.
📐 commitlint
Valide que votre message de commit respecte la convention type(scope): description. Si le format est mauvais → commit bloqué.
Exemple concret
# ❌ Mauvais commit → bloqué
$ git commit -m "fix truc"
⧗   input: fix truc
✖   subject may not be empty [subject-empty]
✖   type may not be empty [type-empty]
husky - commit-msg script failed (code 1)

# ✅ Bon commit → accepté
$ git commit -m "fix(auth): corriger la validation du formulaire"
✔ Commit accepté

📦 Installation (npm / pnpm)

La commande recommandée par la documentation Husky est husky init.

1. Installer tous les packages
npm
npm install --save-dev \
  husky \
  lint-staged \
  @commitlint/cli \
  @commitlint/config-conventional
pnpm
pnpm add --save-dev \
  husky \
  lint-staged \
  @commitlint/cli \
  @commitlint/config-conventional
2. Initialiser Husky (commandes officielles)
npm
npx husky init
pnpm
pnpm exec husky init

✅ Cela crée le dossier .husky/, ajoute le script "prepare": "husky" dans package.json, et génère un hook pre-commit exemple.

3. Ajouter la configuration lint-staged dans package.json
{
  "scripts": {
    "dev": "next dev",
    "prepare": "husky"   // ← généré automatiquement
  },
  "lint-staged": {
    "*.{ts,tsx,js,jsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{json,css,md}": [
      "prettier --write"
    ]
  }
}
🔧 Pourquoi le script prepare ?
Il s'exécute automatiquement après chaque npm install / pnpm install. Tous les développeurs qui clonent le projet auront Husky actif immédiatement, sans configuration supplémentaire.

⚙️ Configurer les hooks Git

Deux fichiers à créer dans le dossier .husky/ contrôlent les moments clés.

📁 Important : Ces fichiers doivent être créés dans le dossier .husky/ à la racine de votre projet.
Hook pre-commit (lancé avant de demander le message)
npm
# .husky/pre-commit
npx lint-staged
pnpm
# .husky/pre-commit
pnpm exec lint-staged
Hook commit-msg (lancé après avoir tapé le message)
npm
# .husky/commit-msg
npx --no -- commitlint --edit $1
pnpm
# .husky/commit-msg
pnpm exec commitlint --edit $1
Structure finale
.husky/
├── _/
│   └── husky.sh        ← généré automatiquement, ne pas modifier
├── pre-commit          ← À créer — lance lint-staged
└── commit-msg          ← À créer — valide le message avec commitlint
Hook optionnel — pre-push (tests avant push)
npm
# .husky/pre-push
npm run test
pnpm
# .husky/pre-push
pnpm test
📌 pre-commit vs commit-msg
pre-commit → vérifie le code (lint-staged).
commit-msg → vérifie le format du message (commitlint). Les deux sont complémentaires.

📏 Configurer commitlint

À la racine du projet, créez commitlint.config.ts (ou .js).

commitlint.config.ts (recommandé pour TypeScript)
import type { UserConfig } from "@commitlint/types";

const config: UserConfig = {
  extends: ["@commitlint/config-conventional"],
  rules: {
    "header-max-length": [2, "always", 100],
    "type-enum": [
      2,
      "always",
      [
        "feat", "fix", "docs", "style",
        "refactor", "test", "chore", "perf", "ci", "revert"
      ],
    ],
  },
};
export default config;
Version JavaScript (commitlint.config.js)
module.exports = {
  extends: ["@commitlint/config-conventional"],
  rules: {
    "header-max-length": [2, "always", 100],
    "type-enum": [
      2,
      "always",
      ["feat", "fix", "docs", "style", "refactor", "test", "chore", "perf", "ci", "revert"]
    ],
  },
};

✍️ Convention de commit (Conventional Commits)

Format que commitlint attend : type(scope): description

Format général
type(scope): description courte

# type        → obligatoire (feat, fix, docs, style, refactor, test, chore, perf, ci, revert)
# scope       → optionnel (ex: auth, api, ui, db)
# description → obligatoire, minuscules, pas de point final
Types avec exemples
feat
feat(auth): ajouter connexion Google
Nouvelle fonctionnalité
fix
fix(cart): corriger calcul total
Correction de bug
refactor
refactor(api): simplifier fetchUser
Réécriture sans changement fonctionnel
chore
chore: mettre à jour dépendances
Maintenance, config, outillage
docs
docs: ajouter guide installation
Documentation uniquement
style
style: formater les fichiers auth
Formatage, espaces, pas de logique
test
test(user): ajouter tests unitaires
Ajout ou correction de tests
perf
perf(images): lazy-loader les images
Amélioration de performance
✅ Valides / ❌ Invalides
✓ feat(auth): ajouter la page de connexion
✓ fix: corriger le crash au démarrage
✓ chore(deps): mettre à jour next vers 15.2
✓ refactor(ui): extraire le composant Button

✗ fix truc                     ← pas de ":" , type invalide
✗ Fix(auth): Corriger bug      ← majuscule interdite
✗ feat(auth): nouveau login.   ← point final interdit
✗ wip: en cours                ← type "wip" non autorisé

🧪 Tester que tout fonctionne

Vérifiez chaque outil indépendamment.

1. Tester commitlint seul
npm
echo "fix truc" | npx commitlint
✖ type may not be empty

echo "fix(auth): corriger" | npx commitlint
✅ Passé
pnpm
echo "fix truc" | pnpm exec commitlint
✖ type may not be empty

echo "fix(auth): corriger" | pnpm exec commitlint
✅ Passé
2. Tester lint-staged seul
npm
npx lint-staged
pnpm
pnpm exec lint-staged
3. Vrai commit bloqué (mauvais format)
$ git add .
$ git commit -m "fix truc"

⧗   input: fix truc
✖   type may not be empty [type-empty]
husky - commit-msg script failed (code 1)
# Bloqué → c'est ce qu'on veut !
4. Vrai commit réussi
$ git commit -m "feat(auth): ajouter la page de connexion"

✔ Preparing lint-staged...
✔ Running tasks for staged files...
✔ Applying modifications from tasks...
[main abc1234] feat(auth): ajouter la page de connexion

📁 Structure finale du projet
mon-projet-next/
├── .husky/
│   ├── _/husky.sh
│   ├── pre-commit      ← À créer dans .husky/
│   └── commit-msg      ← À créer dans .husky/
├── commitlint.config.ts
├── package.json          ← contient "prepare": "husky" + lint-staged
└── next.config.js
👥 Pour les collaborateurs
Quand un développeur clone le projet et lance npm install (ou pnpm install), le script prepare exécute automatiquement husky. Les hooks sont actifs immédiatement, sans aucune configuration manuelle.
⏸️ Désactiver temporairement
HUSKY=0 git commit -m "commit forcé" — utile pour les situations d'urgence.

📖 Basé sur la documentation officielle de Husky — Méthode husky init recommandée