カスタムドキュメント

カスタム Document を使用すると、ページをレンダリングする際に使用される <html> タグと <body> タグを更新できます。

デフォルトの Document をオーバーライドするには、以下のように pages/_document ファイルを作成します:

import { Html, Head, Main, NextScript } from 'next/document'

export default function Document() {
  return (
    <Html lang="en">
      <Head />
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  )
}
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 /> はページを正しくレンダリングするために必須です。

注意点

  • _document で使用される <Head /> コンポーネントは next/head とは異なります。ここで使用する <Head /> コンポーネントは、すべてのページに共通する <head> コードのみに使用してください。<title> タグなどの他のケースでは、ページやコンポーネント内で next/head を使用することを推奨します。
  • <Main /> の外側にあるReactコンポーネントはブラウザによって初期化されません。ここにアプリケーションロジックやカスタムCSS(styled-jsxなど)を追加しないでください。すべてのページで共有コンポーネント(メニューやツールバーなど)が必要な場合は、代わりにレイアウトを参照してください。
  • Document は現在、getStaticPropsgetServerSideProps といったNext.jsのデータフェッチング方法をサポートしていません。

renderPage のカスタマイズ

renderPage のカスタマイズは高度な機能であり、CSS-in-JSのようなライブラリがサーバーサイドレンダリングをサポートする場合にのみ必要です。組み込みの styled-jsx サポートでは必要ありません。

このパターンを使用することは推奨しません。 代わりに、ページとレイアウトのデータをより簡単に取得できるApp Routerへの段階的な移行を検討してください。

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
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 が追加されています。