Como Corrigir IA Colocando Código de Servidor em Componentes do Cliente
Agentes de IA vazam consultas de banco de dados, variáveis de ambiente secretas e APIs Node.js para componentes 'use client', expondo lógica exclusiva do servidor ao bundle do navegador.
O agente adiciona uma diretiva "use client" a um componente que importa Prisma, fs ou uma variável de ambiente secreta — o que envia esse código para o bundle do navegador de cada visitante.
O sintoma
Um componente marcado como "use client" faz uma chamada direta ao banco de dados ou lê um segredo process.env.
"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>;}A compilação pode ser bem-sucedida (Next.js agrupa a importação), mas a página lança um erro em tempo de execução no navegador porque @prisma/client requer APIs Node.js.
Por que isso acontece
O agente vê que os dados são necessários dentro de um componente que também usa estado ou efeitos, e recorre à camada de dados que conhece. Ele não modela a fronteira servidor/cliente nem sabe que componentes "use client" não podem importar módulos exclusivos do Node.js.
Como identificar
"use client"no topo de um arquivo que também importa de@/lib/db,prisma,fs,pathoucrypto.process.env.DATABASE_URLou qualquer variável_SECRET_lida dentro de um arquivo"use client".- A saída de compilação contém
Critical dependency: the request of a dependency is an expressionou um aviso de bundle do Prisma. - O pacote
server-onlyestá ausente do projeto.
Como corrigir
Divida em um componente de servidor pai que busca os dados e um componente de cliente filho que lida com a interatividade.
// 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 accessPrompt de correção
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.Teste
# 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"