Preview Mode

주의: 이 기능은 Draft Mode로 대체되었습니다.

예제

Pages 문서Data Fetching 문서에서 getStaticPropsgetStaticPaths를 사용하여 빌드 타임에 페이지를 사전 렌더링(정적 생성)하는 방법에 대해 이야기했습니다.

정적 생성은 페이지가 헤드리스 CMS에서 데이터를 가져올 때 유용합니다. 하지만 헤드리스 CMS에서 초안을 작성하고 페이지에서 바로 미리보기를 원할 때는 이상적이지 않습니다. 이러한 경우 Next.js가 이 페이지들을 빌드 타임이 아닌 요청 타임에 렌더링하고 게시된 컨텐츠 대신 초안 컨텐츠를 가져오도록 하고 싶을 것입니다. 이와 같이 Next.js가 특정 경우에 정적 생성을 우회하기를 원할 수 있습니다.

Next.js에는 이러한 문제를 해결하는 Preview Mode라는 기능을 제공합니다. 사용 방법은 다음과 같습니다.

Step 1: Create and access a preview API route

Next.js API Routes를 잘 모르는 경우 API Routes 문서을 먼저 참조하십시오.

먼저 미리보기 API route를 만듭니다. 이름은 자유롭게 설정할 수 있습니다 - 예: pages/api/preview.js (TypeScript를 사용하는 경우 .ts).

이 API route에서 응답 객체에 setPreviewData를 호출해야 합니다. setPreviewData의 인수는 객체여야 하며, 이는 getStaticProps에서 사용할 수 있습니다(이후에 더 설명함). 지금은 {}를 사용하겠습니다.

export default function handler(req, res) {
  // ...
  res.setPreviewData({})
  // ...
}

res.setPreviewData는 브라우저에 쿠키를 설정하여 preview mode를 활성화합니다. 이러한 쿠키를 포함한 Next.js로의 모든 요청은 preview mode로 간주되며, 정적으로 생성된 페이지의 동작이 변경됩니다(이후에 더 설명함).

아래와 같이 API route를 만들고 브라우저에서 직접 액세스하여 수동으로 테스트할 수 있습니다:

pages/api/preview.js
// 브라우저에서 수동으로 테스트할 수 있는 간단한 예제입니다.
export default function handler(req, res) {
  res.setPreviewData({})
  res.end('Preview mode enabled')
}

브라우저의 개발자 도구를 열고 /api/preview를 확인하면 이 요청에 __prerender_bypass__next_preview_data 쿠키가 설정되는 것을 확인할 수 있습니다.

Securely accessing it from your Headless CMS

실제로는 헤드리스 CMS에서 이 라우트 핸들러를 보안 방식으로 호출하고 싶을 것입니다. 사용 중인 헤드리스 CMS에 따라 구체적인 단계는 다를 수 있지만, 다음과 같은 일반적인 단계를 따를 수 있습니다.

이 단계는 사용 중인 헤드리스 CMS가 사용자 정의 미리보기 URL 설정을 지원한다고 가정합니다. 지원하지 않는 경우에도 이 방법을 사용하여 미리보기 URL을 보호할 수 있지만, 미리보기 URL을 수동으로 구성하고 접근해야 합니다.

먼저, 원하는 토큰 생성기를 사용하여 시크릿 토큰 문자열을 생성해야 합니다. 이 시크릿은 Next.js 앱과 헤드리스 CMS만 알고 있어야 합니다. 이 시크릿은 CMS에 액세스할 수 없는 사람들이 미리보기 URL에 접근하는 것을 방지합니다.

두 번째, 헤드리스 CMS가 사용자 정의 미리보기 URL 설정을 지원하는 경우, 다음을 미리보기 URL로 지정합니다. 이는 미리보기 API route가 pages/api/preview.js에 위치한다고 가정합니다.

Terminal
https://<your-site>/api/preview?secret=<token>&slug=<path>
  • <your-site>는 배포 도메인이어야 합니다.
  • <token>은 생성한 시크릿 토큰으로 교체해야 합니다.
  • <path> 는 미리보기 하려는 페이지의 경로여야 합니다. /posts/foo를 보고자 한다면 &slug=/posts/foo를 사용해야 합니다.

사용중인 헤드리스 CMS가 변수 삽입을 지원하는 경우 <path>를 CMS 데이터에 따라 동적으로 설정할 수 있습니다: &slug=/posts/{entry.fields.slug}

마지막으로, 미리보기 API route에서:

  • 시크릿이 일치하고 slug 매개변수가 존재하는지 확인합니다(존재하지 않으면 요청이 실패해야 합니다).
  • res.setPreviewData를 호출합니다.
  • 그런 다음 브라우저를 slug로 지정된 경로로 리디렉션합니다(다음 예제에서는 307 redirect (opens in a new tab)을 사용합니다).
export default async (req, res) => {
  // 시크릿과 다음 매개변수를 확인합니다.
  // 이 시크릿은 이 API route와 CMS만 알고 있어야 합니다.
  if (req.query.secret !== 'MY_SECRET_TOKEN' || !req.query.slug) {
    return res.status(401).json({ message: 'Invalid token' })
  }
 
  // 제공된 `slug`가 존재하는지 확인하기 위해 헤드리스 CMS를 가져옵니다.
  // getPostBySlug는 헤드리스 CMS에 필요한 fetching 로직을 구현합니다.
  const post = await getPostBySlug(req.query.slug)
 
  // slug가 존재하지 않으면 Preview Mode가 활성화되지 않도록 합니다.
  if (!post) {
    return res.status(401).json({ message: 'Invalid slug' })
  }
 
  // 쿠키를 설정하여 Preview Mode를 활성화합니다.
  res.setPreviewData({})
 
  // 가져온 게시물의 경로로 리디렉션합니다.
  // req.query.slug로 리디렉션하지 않는 이유는 open redirect 취약점이 발생할 수 있기 때문입니다.
  res.redirect(post.slug)
}

성공하면 브라우저는 설정된 preview mode 쿠키와 함께 보고자 하는 경로로 리디렉션됩니다.

Step 2: Update getStaticProps

다음 단계는 getStaticProps를 업데이트하여 preview mode를 지원하는 것입니다.

Preview mode 쿠키가 설정된 상태로 getStaticProps가 있는 페이지를 요청하면 getStaticProps빌드 타임이 아닌 요청 타임에 호출됩니다.

또한, context 객체와 함께 호출되며:

  • context.previewtrue입니다.
  • context.previewDatasetPreviewData에 사용된 인수와 동일합니다.
export async function getStaticProps(context) {
  // preview mode 쿠키가 설정된 상태로 이 페이지를 요청하면:
  //
  // - context.preview는 true가 됩니다.
  // - context.previewData는 `setPreviewData`에 사용된 인수와 동일합니다.
}

우리는 미리보기 API route에서 res.setPreviewData({})를 사용했으므로 context.previewData{}가 됩니다. 필요하다면 미리보기 API route에서 getStaticProps로 세션 정보를 전달하는 데 사용할 수 있습니다.

getStaticPaths를 사용하는 경우, context.params도 사용할 수 있습니다.

Fetch preview data

getStaticProps를 업데이트하여 context.preview 및/또는 context.previewData에 따라 다른 데이터를 가져올 수 있습니다.

예를 들어, 헤드리스 CMS가 초안 게시물에 대해 다른 API 엔드포인트를 가지고 있는 경우, 아래와 같이 API 엔드포인트 URL을 수정하는 데 context.preview를 사용할 수 있습니다:

export async function getStaticProps(context) {
  // context.preview가 true이면, 초안 데이터를 요청하기 위해 API 엔드포인트에 "/preview"를 추가합니다.
  // 이는 사용하는 헤드리스 CMS에 따라 다릅니다.
  const res = await fetch(`https://.../${context.preview ? 'preview' : ''}`)
  // ...
}

이제 미리보기 API route(시크릿 및 slug 포함)를 헤드리스 CMS 또는 수동으로 접근하면 미리보기 컨텐츠를 볼 수 있어야 합니다. 초안을 게시하지 않고 업데이트하더라도 초안을 미리 볼 수 있어야 합니다.

헤드리스 CMS에 이를 미리보기 URL로 설정하거나 수동으로 접근하면 미리보기를 볼 수 있습니다.

Terminal
https://<your-site>/api/preview?secret=<token>&slug=<path>

More Details

참고: 렌더링 중 next/routerisPreview 플래그를 노출합니다. 자세한 내용은 router object docs를 참조하십시오.

Specify the Preview Mode duration

setPreviewData는 option 객체인 두 번째 매개 변수를 사용합니다. 이는 다음 키들을 사용합니다:

  • maxAge: 미리보기 세션이 지속되는 시간을 초 단위로 지정합니다.
  • path: 쿠키가 적용될 경로를 지정합니다. 기본값은 /이며, 이는 모든 경로에 대해 preview mode를 활성화합니다.
setPreviewData(data, {
  maxAge: 60 * 60, // preview mode 쿠키는 1시간 후에 만료됩니다.
  path: '/about', // preview mode 쿠키는 /about 경로에 적용됩니다.
})

Clear the Preview Mode cookies

기본적으로, preview mode 쿠키에는 만료 날짜가 설정되지 않으므로 브라우저를 닫을 때 미리보기 세션이 종료됩니다.

Preview mode 쿠키를 수동으로 제거하려면 clearPreviewData()를 호출하는 API route를 만듭니다:

pages/api/clear-preview-mode-cookies.js
export default function handler(req, res) {
  res.clearPreviewData({})
}

그런 다음 /api/clear-preview-mode-cookies 에 요청을 보내 API Route를 호출합니다. next/link를 사용하여 이 라우트를 호출하는 경우 링크 사전 로딩 중에 clearPreviewData를 호출하지 않도록 prefetch={false}를 설정해야 합니다.

setPreviewData 호출에서 경로를 지정한 경우, 동일한 경로를 clearPreviewData에 전달해야 합니다:

pages/api/clear-preview-mode-cookies.js
export default function handler(req, res) {
  const { path } = req.query
 
  res.clearPreviewData({ path })
}

previewData size limits

객체를 setPreviewData에 전달하여 getStaticProps에서 사용할 수 있습니다. 그러나 데이터가 쿠키에 저장되므로 크기 제한이 있습니다. 현재 미리보기 데이터는 2KB로 제한됩니다.

Works with getServerSideProps

Preview mode는 getServerSideProps에서도 작동합니다. context 객체에 previewpreviewData가 포함되어 사용할 수 있습니다.

참고: Preview Mode를 사용할 때 Cache-Control 헤더를 설정하면 우회할 수 없으므로 설정하지 않아야 합니다. 대신, ISR을 사용하는 것을 추천합니다.

Works with API Routes

API Routes는 요청 객체에서 previewpreviewData에 접근할 수 있습니다. 예를 들어:

export default function myApiRoute(req, res) {
  const isPreview = req.preview
  const previewData = req.previewData
  // ...
}

Unique per next build

우회 쿠키 값과 previewData 암호화를 위한 개인 키는 next build가 완료될 때 변경됩니다. 이를 통해 우회 쿠키를 추측할 수 없도록 합니다.

참고: 로컬에서 HTTP를 통해 Preview Mode를 테스트하려면 브라우저에서 서드 파티 쿠키와 로컬 스토리지 액세스를 허용해야 합니다.