проектdocs/Agents/rules/architecture-server-components.md
architecture-server-components.md
Обновлён 1 апр. 2026 г., 12:41 · 0 комментариев
title: Default to Server Components, Use Client Only When Needed impact: CRITICAL impactDescription: Reduces JavaScript bundle size by 40-60% and improves initial load tags: architecture, nextjs, rsc, server-components, ssr
Паспорт документа
- Статус документа: living standard
- Актуально на: 28 марта 2026 года
- Владелец: backend/platform-команда
- Пересмотр: при изменении инженерной практики, CI/CD, архитектурных правил или локального workflow
- Область применения: внутренние rule/reference-card документы для инженерной команды
- Связанные документы:
Default to Server Components, Use Client Only When Needed
Impact: CRITICAL (Reduces JS bundle size by 40-60%)
Every Next.js component is a Server Component by default. Only add "use client" when the component genuinely requires browser APIs or interactivity.
Requires "use client":
- Event handlers (
onClick,onChange,onSubmit) - React hooks (
useState,useEffect,useRef) - Browser APIs (
window,document,localStorage) - Third-party client libraries (map widgets, animation libraries)
Does NOT require "use client":
- Data fetching and display
- Static content rendering
- Layout and navigation structure
- Conditional rendering based on props/data
Incorrect (unnecessary client component):
"use client"; // Why? This doesn't need any client features!
import { api } from '@/lib/api';
export default function ItemDetailPage({ params }) {
const [item, setItem] = useState(null);
useEffect(() => {
api.catalog.getItemBySlug(params.slug).then(setItem);
}, []);
if (!item) return <Skeleton />;
return <div>{item.name}</div>;
}
Correct (Server Component with client islands):
// app/item/[slug]/page.tsx — Server Component (no directive)
import { api } from '@/lib/api';
import { notFound } from 'next/navigation';
import { ItemActions } from './ItemActions'; // Client island
export default async function ItemDetailPage({ params }: { params: { slug: string } }) {
const item = await api.catalog.getItemBySlug(params.slug);
if (!item) notFound();
return (
<div>
<h1>{item.name}</h1>
<p>{item.description}</p>
{/* Only this part is a Client Component */}
<ItemActions itemId={item.id} />
</div>
);
}
// app/item/[slug]/ItemActions.tsx — Client Component (needs interactivity)
"use client";
import { useTranslations } from 'next-intl';
export function ItemActions({ itemId }: { itemId: string }) {
const t = useTranslations('item');
const [showModal, setShowModal] = useState(false);
return <button onClick={() => setShowModal(true)}>{t('submitLead')}</button>;
}
Pattern: Client Islands Keep the page as a Server Component. Extract only the interactive parts into small Client Components ("islands") and pass serializable data as props.