Docs
Routing
Custom Document

Custom Document

사용자 정의 Document페이지를 렌더링하는 데 사용되는 <html><body> 태그를 업데이트할 수 있습니다.

기본 Document를 오버라이드 하려면 아래와 같이 pages/_document 파일을 생성하세요.

pages/_document.tsx
import { Html, Head, Main, NextScript } from 'next/document'
 
export default function Document() {
  return (
    <Html lang="en">
      <Head />
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  )
}
pages/_document.jsx
import { Html, Head, Main, NextScript } from 'next/document'
 
export default function Document() {
  return (
    <Html lang="en">
      <Head />
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  )
}

알아두면 유용한 정보

  • _document는 서버에서만 렌더링되므로, 이 파일에서는 onClick과 같은 이벤트 핸들러를 사용할 수 없습니다.
  • 페이지가 제대로 렌더링되려면 <Html>, <Head />, <Main /><NextScript />가 필요합니다.

Caveats

  • _document에 사용된 <Head /> 컴포넌트는 next/head와 동일하지 않습니다. 여기에 사용된 <Head /> 컴포넌트는 모든 페이지에 공통으로 적용되는 <head> 코드에만 사용해야 합니다. <title> 태그와 같은 다른 모든 경우에는 페이지 또는 컴포넌트에서 next/head를 사용하는 것이 좋습니다.
  • <Main /> 외부의 React 컴포넌트는 브라우저에서 초기화되지 않습니다. 여기에 애플리케이션 로직이나 커스텀 CSS(예: styled-jsx)를 추가하지 마세요. 모든 페이지에 공유되는 컴포넌트(메뉴 또는 툴바)가 필요한 경우 레이아웃을 대신 참고하세요.
  • Document는 현재 getStaticProps 또는 getServerSideProps와 같은 Next.js 데이터 패칭 메서드를 지원하지 않습니다.

Customizing renderPage

renderPage 커스터마이징은 고급 기술이며 서버 사이드 렌더링을 지원하기 위해 CSS-in-JS와 같은 라이브러리에서만 필요합니다. 내장된 styled-jsx 지원에는 필요하지 않습니다.

이 패턴을 사용하지 않는 것이 좋습니다. 대신 페이지와 레이아웃에 대한 데이터를 더 쉽게 가져올 수 있는 App Router를 점진적으로 도입하는 것을 고려하세요.

pages/_document.tsx
import Document, {
  Html,
  Head,
  Main,
  NextScript,
  DocumentContext,
  DocumentInitialProps,
} from 'next/document'
 
class MyDocument extends Document {
  static async getInitialProps(
    ctx: DocumentContext,
  ): Promise<DocumentInitialProps> {
    const originalRenderPage = ctx.renderPage
 
    // React 렌더링 로직을 동기적으로 실행합니다.
    ctx.renderPage = () =>
      originalRenderPage({
        // 전체 React 트리를 래핑하는 데 유용합니다.
        enhanceApp: (App) => App,
        // 페이지별로 래핑하는 데 유용합니다.
        enhanceComponent: (Component) => Component,
      })
 
    //  부모의 `getInitialProps`를 실행하며, 이제 커스텀 `renderPage`가 포함됩니다.
    const initialProps = await Document.getInitialProps(ctx)
 
    return initialProps
  }
 
  render() {
    return (
      <Html lang="en">
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}
 
export default MyDocument
pages/_document.jsx
import Document, { Html, Head, Main, NextScript } from 'next/document'
 
class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const originalRenderPage = ctx.renderPage
 
    // React 렌더링 로직을 동기적으로 실행합니다.
    ctx.renderPage = () =>
      originalRenderPage({
        // 전체 React 트리를 래핑하는 데 유용합니다.
        enhanceApp: (App) => App,
        // 페이지별로 래핑하는 데 유용합니다.
        enhanceComponent: (Component) => Component,
      })
 
    //  부모의 `getInitialProps`를 실행하며, 이제 커스텀 `renderPage`가 포함됩니다.
    const initialProps = await Document.getInitialProps(ctx)
 
    return initialProps
  }
 
  render() {
    return (
      <Html lang="en">
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}
 
export default MyDocument

알아두면 유용한 정보

  • _documentgetInitialProps는 클라이언트 측 전환 중에는 호출되지 않습니다.
  • _documentctx 객체는 getInitialProps에서 받은 것과 동일하며, renderPage가 추가되어 있습니다.