# Comment corriger l'IA plaçant du code serveur dans les composants client

> Les agents IA fuient les requêtes de base de données, les variables d'environnement secrètes et les API Node.js dans les composants 'use client', exposant la logique serveur au bundle du navigateur.

**Type:** Failure  
**Tools:** Cursor, Claude Code, Codex, Windsurf  
**Stack:** Next.js, TypeScript  
**Updated:** 2026-06-08

---

L'agent ajoute une directive `"use client"` à un composant qui importe Prisma, `fs` ou une variable d'environnement secrète — ce qui expédie ce code dans le bundle du navigateur de chaque visiteur.

## Le symptôme

Un composant marqué `"use client"` effectue un appel direct à la base de données ou lit un secret `process.env`.

```tsx
"use client";
import { db } from "@/lib/db"; // Prisma client — Node.js only
import { useState, useEffect } from "react";

export function UserCard({ id }: { id: string }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    // db is a Node.js module — this will throw at runtime in the browser
    db.user.findUnique({ where: { id } }).then(setUser);
  }, [id]);

  return <div>{user?.name}</div>;
}
```

La construction peut réussir (Next.js regroupe l'import) mais la page génère une erreur d'exécution dans le navigateur car `@prisma/client` nécessite les API Node.js.

## Pourquoi cela arrive

L'agent voit que des données sont nécessaires à l'intérieur d'un composant qui utilise aussi l'état ou les effets, et se tourne vers la couche de données qu'il connaît. Il ne modélise pas la limite serveur/client et ne sait pas que les composants `"use client"` ne peuvent pas importer des modules réservés à Node.js.

## Comment le repérer

- `"use client"` en haut d'un fichier qui importe aussi depuis `@/lib/db`, `prisma`, `fs`, `path` ou `crypto`.
- `process.env.DATABASE_URL` ou toute variable `_SECRET_` lue dans un fichier `"use client"`.
- La sortie de construction contient `Critical dependency: the request of a dependency is an expression` ou un avertissement de bundle Prisma.
- Le package `server-only` est absent du projet.

## Comment le corriger

Divisez en un composant serveur parent qui récupère les données, et un composant client enfant qui gère l'interactivité.

```tsx
// app/users/[id]/page.tsx — Server Component (no directive)
import { db } from "@/lib/db";
import { UserCard } from "./UserCard";

export default async function UserPage({ params }: { params: { id: string } }) {
  const user = await db.user.findUniqueOrThrow({ where: { id: params.id } });
  // Serialize — pass plain data, not the Prisma object
  return <UserCard name={user.name} email={user.email} />;
}
```

```tsx
// app/users/[id]/UserCard.tsx — Client Component
"use client";
import { useState } from "react";

export function UserCard({ name, email }: { name: string; email: string }) {
  const [expanded, setExpanded] = useState(false);
  return (
    <div>
      <p>{name}</p>
      {expanded && <p>{email}</p>}
      <button onClick={() => setExpanded((v) => !v)}>Toggle</button>
    </div>
  );
}
```

```txt
[ ] Install "server-only" and import it at the top of every server-side lib file
[ ] No db/prisma imports in "use client" files
[ ] No process.env secrets read in "use client" files
[ ] Server Component fetches data; Client Component receives plain props
[ ] Use Server Actions (not useEffect+fetch) when a client interaction needs db access
```

## Prompt de correction

```txt title="Fix Prompt"
This "use client" component imports server-only modules (Prisma, fs, or secret
env vars). Refactor it: move all data fetching into an async Server Component
parent, pass only serializable props to the client component, and keep "use
client" only on the part that needs browser APIs or React state. Add
"server-only" to any shared lib files that must never reach the browser.
```

## Test

```bash
# List all "use client" files that also import known server-only packages
grep -rl '"use client"' app/ | xargs grep -l "prisma\|@/lib/db\|\"fs\"\|\"path\"\|\"crypto\"" && echo "FAIL: server code in client component" || echo "OK"
```