Engineering

Next.js 16

App Router와 Server Components 중심으로 Next.js 16 문서 앱을 설계하고 실패를 피합니다.

검증일 근거 자료

렌더링 경계를 먼저 정하기

App Router의 기본은 Server Component입니다. 문서 본문, 내비게이션 데이터, SEO 메타데이터는 서버에서 만들고 검색 대화상자, 테마 선택, 스크롤 스파이처럼 브라우저 상태가 필요한 작은 경계만 Client Component로 둡니다. 이 구분은 초기 JavaScript와 직렬화 비용을 줄입니다.

export default async function Page({ params }: PageProps) {
  const { locale, slug } = await params;
  const document = await getDocument(locale, slug);
  return <DocumentPage document={document} />;
}

MDX 파이프라인

@next/mdx를 App Router에서 사용하려면 루트의 mdx-components.tsx가 필요합니다. GFM과 frontmatter는 remark, heading id는 rehype 단계에서 처리합니다. 동적 import 경로를 임의 문자열로 만들기보다 정적 loader map을 두면 번들 추적과 404 동작이 명확해집니다.

캐시와 병렬성

독립적인 I/O는 먼저 시작하고 Promise.all로 기다립니다. 같은 요청에서 반복되는 서버 조회는 cache()로 중복을 제거합니다. 매 요청 전역 상태를 모듈 변수에 저장하면 사용자 간 데이터가 섞일 수 있으므로 피합니다.

실전 팁

  • generateStaticParamsdynamicParams = false를 함께 사용해 알려지지 않은 문서를 404로 만듭니다.
  • locale별 alternates.languages를 생성해 canonical과 hreflang을 일치시킵니다.
  • 무거운 검색 코드는 사용자가 검색을 열 때 import하거나 인덱스를 fetch합니다.
  • 서버에서 이미 가진 전체 원문을 Client Component props로 넘기지 않습니다.

실패 사례

전체 레이아웃을 Client Component로 만들기

Provider가 필요하다는 이유로 루트 전체에 "use client"를 붙이면 정적 문서까지 클라이언트 번들에 들어갑니다. 상태 provider를 작은 ClientShell로 분리하고 본문 children은 서버에서 렌더링한 채 슬롯으로 전달합니다.

런타임 파일 시스템 의존

요청마다 content 디렉터리를 탐색하면 배포 추적과 캐시가 불안정해집니다. 빌드 전에 manifest와 검색 인덱스를 생성하고 페이지는 정적 loader와 manifest를 읽게 합니다.