So beheben Sie, dass KI Server-Code in Client-Komponenten platziert
KI-Agenten geben Datenbankabfragen, geheime Umgebungsvariablen und Node.js-APIs in `'use client'`-Komponenten preis, wodurch serverseitige Logik im Browser-Bundle offengelegt wird.
Der Agent fügt eine "use client"-Direktive zu einer Komponente hinzu, die Prisma,
fs oder eine geheime Umgebungsvariable importiert – was diesen Code in das Browser-Bundle jedes Besuchers packt.
Das Symptom
Eine Komponente, die als "use client" markiert ist, führt einen direkten Datenbankaufruf durch oder liest ein
process.env-Geheimnis.
"use client";import { db } from "@/lib/db"; // Prisma client — Node.js onlyimport { 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>;}Der Build kann erfolgreich sein (Next.js bündelt den Import), aber die Seite wirft einen Laufzeitfehler im Browser,
weil @prisma/client Node.js-APIs benötigt.
Warum es passiert
Der Agent erkennt, dass Daten in einer Komponente benötigt werden, die auch State oder Effekte verwendet, und greift auf die ihm bekannte Datenebene zu. Er modelliert nicht die Server/Client-Grenze und weiß nicht, dass "use client"-Komponenten keine Node.js-exklusiven Module importieren können.
Wie man es erkennt
"use client"am Anfang einer Datei, die auch aus@/lib/db,prisma,fs,pathodercryptoimportiert.process.env.DATABASE_URLoder eine beliebige_SECRET_-Variable, die in einer"use client"-Datei gelesen wird.- Die Build-Ausgabe enthält
Critical dependency: the request of a dependency is an expressionoder eine Prisma-Bundle-Warnung. - Das Paket
server-onlyfehlt im Projekt.
Wie man es behebt
Teilen Sie es auf in eine Server-Komponente als Elternkomponente, die abruft, und eine Client-Komponente als Kind, die die Interaktivität übernimmt.
// 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} />;}// 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> );}[ ] 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 accessKorrektur-Prompt
This "use client" component imports server-only modules (Prisma, fs, or secretenv vars). Refactor it: move all data fetching into an async Server Componentparent, pass only serializable props to the client component, and keep "useclient" 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
# List all "use client" files that also import known server-only packagesgrep -rl '"use client"' app/ | xargs grep -l "prisma\|@/lib/db\|\"fs\"\|\"path\"\|\"crypto\"" && echo "FAIL: server code in client component" || echo "OK"