# Regla: Hooks de Pre-commit y CI — Next.js

Los hooks de pre-commit y las verificaciones de CI detectan los errores más
comunes en Next.js App Router: código cliente innecesario, fetch sin caché
configurado, imágenes sin optimizar y errores de compilación.

---

## next lint — verificación de linting

Ejecutar antes de cada commit:

```bash
next lint
```

- Si reporta errores o warnings: **bloquear el commit**.
- La configuración de ESLint debe incluir `next/core-web-vitals` que cubre
  reglas específicas de Next.js sobre Image, Link y rendimiento.
- En proyectos con monorepo: `next lint --dir apps/web`.

---

## next build — verificación de compilación

En CI, en cada PR:

```bash
next build
```

- Si el build falla: **bloquear el merge**.
- Los errores de TypeScript con `strict: true` también fallan el build.
  El flag `ignoreBuildErrors: true` en `next.config.js` está prohibido en producción.
- El build también valida que todos los Server Components son correctamente `async`
  y que los `"use client"` no intentan importar módulos solo del servidor.

---

## Detección de console.log en código no-test

```bash
# En hook pre-commit o CI
git diff --cached --name-only \
  | grep -E '\.(ts|tsx)$' \
  | grep -v '\.test\.' \
  | grep -v '\.spec\.' \
  | grep -v '__tests__' \
  | xargs grep -n 'console\.log\|console\.debug\|console\.warn' 2>/dev/null
```

- Si encuentra `console.log` fuera de archivos de test: **bloquear el commit**.
- `console.error` en catch de errores inesperados es aceptable si viene acompañado
  de un comentario y va a ser reemplazado por el logger del proyecto.

---

## Verificación de "use client" potencialmente innecesario

Detectar archivos con `"use client"` que no contienen hooks de estado ni eventos:

```bash
# Script de verificación — reporta como advertencia, no bloquea
git diff --cached --name-only | grep '\.tsx$' | while read archivo; do
  if grep -q '"use client"' "$archivo"; then
    if ! grep -qE 'useState|useReducer|useEffect|useRef|onClick|onChange|onSubmit|useContext' "$archivo"; then
      echo "ADVERTENCIA: $archivo tiene \"use client\" pero no usa hooks ni eventos. Verificar si es necesario."
    fi
  fi
done
```

- Este check genera **advertencia**, no bloquea. El desarrollador revisa y decide.
- El revisor del PR verifica la justificación antes de aprobar.

---

## Verificación de fetch() sin configuración de caché

En Next.js App Router, un `fetch()` sin configuración de caché usa el valor por
defecto que puede cambiar entre versiones. Configurar explícitamente:

```bash
# Detectar fetch sin next: o cache: configurado
grep -rn "fetch(" app/ lib/ --include='*.ts' --include='*.tsx' \
  | grep -v '\.test\.' \
  | grep -v 'next:\|cache:' \
  | grep -v '// no-cache-ok'
```

- Si encuentra `fetch(` sin `{ next: { revalidate: N } }` ni `{ cache: 'no-store' }`:
  **reportar como advertencia en el PR**.
- El desarrollador agrega la configuración correcta o el comentario `// no-cache-ok`
  con justificación.

**Referencia rápida de cuándo usar qué:**

| Situación | Configuración |
|-----------|--------------|
| Datos que cambian frecuentemente | `{ cache: 'no-store' }` |
| Datos semi-estáticos (catálogos) | `{ next: { revalidate: 3600 } }` |
| Datos que cambian por evento | `{ next: { tags: ['nombre-tag'] } }` |
| Datos completamente estáticos | Sin config (caché indefinido en build) |

---

## Verificación de imágenes sin Image component

```bash
# Detectar <img> nativo en archivos TSX (excluir comentarios y strings)
git diff --cached --name-only | grep '\.tsx$' | xargs grep -n '<img ' 2>/dev/null \
  | grep -v '^\s*//' \
  | grep -v 'data-testid'
```

- Si encuentra `<img` en archivos `.tsx`: **bloquear el commit**.
- Excepción: imágenes dentro de `dangerouslySetInnerHTML` (ya tienen su propio problema).
- El componente `<Image>` de `next/image` optimiza automáticamente el formato,
  el tamaño y la carga lazy. Usar siempre.

---

## Script de pre-commit completo (referencia)

```bash
#!/usr/bin/env bash
set -e

echo "==> Verificando linting (next lint)..."
npx next lint --quiet || {
  echo "ERROR: Errores de ESLint. Corregir antes de commitear."
  exit 1
}

echo "==> Verificando formato (Prettier)..."
npx prettier --check . || {
  echo "ERROR: Hay archivos sin formatear. Ejecutar: npx prettier --write ."
  exit 1
}

echo "==> Verificando console.log fuera de tests..."
ARCHIVOS=$(git diff --cached --name-only | grep -E '\.(ts|tsx)$' | grep -v '\.test\.\|\.spec\.\|__tests__' || true)
if [ -n "$ARCHIVOS" ]; then
  if echo "$ARCHIVOS" | xargs grep -ln 'console\.log\|console\.debug' 2>/dev/null; then
    echo "ERROR: Eliminar console.log/debug antes de commitear."
    exit 1
  fi
fi

echo "==> Verificando <img> sin next/image..."
ARCHIVOS_TSX=$(git diff --cached --name-only | grep '\.tsx$' || true)
if [ -n "$ARCHIVOS_TSX" ]; then
  if echo "$ARCHIVOS_TSX" | xargs grep -ln '<img ' 2>/dev/null; then
    echo "ERROR: Usar <Image> de next/image en lugar de <img>."
    exit 1
  fi
fi

echo "==> Pre-commit: OK"
```

---

## Resumen de qué bloquea qué

| Verificación | Pre-commit | CI / PR | Severidad |
|-------------|-----------|---------|-----------|
| `next lint` | Bloquea | Bloquea | Error |
| Prettier | Bloquea | Bloquea | Error |
| `console.log` | Bloquea | Bloquea | Error |
| `<img>` nativo | Bloquea | Bloquea | Error |
| `next build` | No | Bloquea merge | Error |
| `"use client"` sin hooks | Advertencia | Advertencia | Warning |
| `fetch()` sin caché config | Advertencia | Advertencia | Warning |
| `npm audit` HIGH/CRITICAL | No | Bloquea merge | Error |

---

## Checklist de hooks antes de activar en un proyecto nuevo

- [ ] `next lint` configurado y ejecutado en pre-commit
- [ ] Prettier configurado con `.prettierrc` versionado
- [ ] Script de pre-commit instalado con `husky` o similar
- [ ] Pipeline de CI tiene los pasos: lint, prettier, build, test, audit
- [ ] `strict: true` en `tsconfig.json` para que el build detecte errores de tipos
- [ ] `ignoreBuildErrors` NO está en `next.config.js`
