profound-logoProfound CMS
⌘K
Admin
All Systems Operational
Powered By
profound-logo

편집 모드 지원이 있는 정적 렌더링

문서 사이트가 CMS 편집 모드 기능을 유지하면서 어떻게 빠른 정적 페이지 로드를 달성하는지 설명합니다

Continue Reading
Previous‹관리자 패널 프록시 설정Next템플릿 빌더에서 스크립팅›

하이브리드

렌더러 프로젝트매개변수 라우팅컴포넌트 유형Sse관리자 패널 프록시 설정편집 모드 지원이 있는 정적 렌더링템플릿 빌더에서 스크립팅Create Profound Next

헤드리스

빠른 시작JSON과 Claude 코드Component Zod Pull

Mcp

Mcp

CMS 기능

기능 문서 템플릿템플릿 빌더 기능기능 번역기기능 조직

동기부여

우리의 접근법

용어

하이브리드 대 헤드리스

이 가이드는 CMS 편집 모드 기능을 유지하면서 문서 사이트가 어떻게 빠른 정적 페이지 로드를 달성하는지 설명합니다.

이중 라우트 아키텍처

동일한 콘텐츠에 대해 두 가지 라우트를 사용합니다:

app/
├── [...slug]/page.tsx          # 프로덕션: force-static (빠름)
└── preview/[...slug]/page.tsx  # 편집 모드: force-dynamic (searchParams 읽음)

프록시 미들웨어가 편집 모드 요청을 투명하게 다시 씁니다:

사용자 요청: /en/headless/quickstart?edit_mode=true
       ↓
프록시가 ?edit_mode=true 감지
       ↓
내부 리라이트: /preview/en/headless/quickstart?edit_mode=true
       ↓
동적 라우트가 편집 래퍼로 렌더링

사용자는 URL에서 /preview 를 전혀 보지 않습니다 - 이는 내부 리라이트입니다.

작동 방식

프로덕션 경로(기본값)

// app/[...slug]/page.tsx
export const dynamic = 'force-static';
export const revalidate = 60;

export default async function Page({ params }) {
  // searchParams 없음 - 페이지는 완전한 정적 페이지입니다
  return
  • 페이지는 빌드 시점에 미리 렌더링됩니다
  • CDN 엣지 캐시에서 즉시 제공됩니다
  • 안전장치로 60초마다 재검증(ISR)합니다

편집 모드 경로

// app/preview/[...slug]/page.tsx
export const dynamic = 'force-dynamic';

export default async function PreviewPage({ params, searchParams }) {
  // searchParams 사용 가능 - edit_mode를 감지할 수 있음
  return <ParametricRoutePage params={params} 
  • 모든 요청마다 렌더링됩니다
  • URL에서 ?edit_mode=true 를 읽을 수 있습니다
  • CMS 편집 가능한 래퍼와 블록 윤곽선으로 렌더링합니다

프록시 리라이트

// src/proxy.ts
export const proxy = async (request: NextRequest) => {
  const { pathname, searchParams } = request.nextUrl;

  const editMode = searchParams.get('edit_mode');

성능 비교

시나리오응답 시간렌더링
프로덕션 페이지(캐시됨)~50-100msCDN에서 정적 제공
프로덕션 페이지(만료됨)~50-100ms + 백그라운드 새로고침정적 후 ISR
편집 모드~500-1500ms동적 SSR

ISR(Incremental Static Regeneration) 이해하기

revalidate = 60 설정은 ISR을 활성화합니다. 이는 페이지가 60초마다 다시 계산된다는 의미가 아닙니다.

ISR은 stale-while-revalidate 패턴을 사용합니다:

요청 도착:
  → 캐시된 페이지가 60초 미만인가? → 캐시에서 제공(즉시)
  → 캐시된 페이지가 60초 초과인가? → 오래된 캐시 제공(즉시)
                                + 다음 요청을 위한 백그라운드 재검증

요청이 없으면 = 재계산도 없습니다. 영원히.

예시:

  • 페이지가 오전 10시에 캐시됨
  • 오후 3시까지 방문자 없음
  • 오후 3시에 첫 방문자는 오래된 캐시를 즉시 받음
  • 백그라운드 새로고침이 수행되고, 다음 방문자는 최신 콘텐츠를 받음

60초 윈도우는 안전장치입니다. 이상적으로는 CMS 콘텐츠가 변경될 때 웹훅을 통한 온디맨드 재검증을 사용합니다.

각 라우트를 사용할 때

사용 사례URL사용되는 라우트
일반 탐색/en/headless/quickstart정적
CMS 템플릿 빌더/en/headless/quickstart?edit_mode=true프리뷰(리라이트를 통해)
AI 블록 프리뷰/en/headless/quickstart?ai_preview=1프리뷰(리라이트를 통해)

왜 동적 렌더링만 사용하지 않을까요?

간단한 접근 방식(force-static 없음, 프리뷰 라우트 없음)은 동작하지만 느립니다:

// 간단한 접근 방식 - 동작하지만 요청당 약 1-2초
export default async function Page({ params, searchParams }) {
  return <ParametricRoutePage params={params} searchParams={searchParams} />;
}

이 방식은 모든 요청마다 동적으로 렌더링합니다. 많은 페이지를 가진 문서 사이트에서는 다음과 같습니다:

  • 모든 페이지에서 콜드 스타트 발생
  • CDN 엣지 캐시의 이점 없음
  • 밀리초 대신 1-2초의 로드 시간

이중 라우트 아키텍처는 독자를 위한 정적 속도와 편집자를 위한 동적 기능을 모두 제공합니다.

<
ParametricRoutePage
params
={
params
} />;
}
searchParams
={
searchParams
} />;
}
const
aiPreview
=
searchParams.
get
(
'ai_preview'
);
// edit_mode 또는 ai_preview가 있으면 프리뷰 라우트로 리라이트
if ((editMode === 'true' || editMode === '1' || aiPreview) && !pathname.startsWith('/preview')) {
const url = request.nextUrl.clone();
url.pathname = `/preview${pathname}`;
return NextResponse.rewrite(url);
}
return NextResponse.next();
};