首页
/ Next.js 自定义 Document 全面指南

Next.js 自定义 Document 全面指南

2025-07-05 01:39:18作者:幸俭卉

什么是自定义 Document?

在 Next.js 项目中,_document 文件是一个特殊的服务器端渲染组件,它允许开发者自定义整个应用的 HTML 文档结构。与常规页面组件不同,_document 只在服务器端执行,用于控制 <html><body> 标签等基础文档结构。

为什么需要自定义 Document?

默认情况下,Next.js 会自动生成一个基本的 HTML 文档结构。但在以下场景中,你可能需要自定义 _document

  1. 需要为所有页面设置统一的 HTML 属性(如 lang 属性)
  2. 需要在文档头部添加全局的 meta 标签或脚本
  3. 需要使用 CSS-in-JS 库并需要服务器端渲染支持
  4. 需要在文档中添加自定义的全局内容

基础实现方式

创建一个自定义 Document 非常简单,只需在 pages 目录下创建 _document.tsx_document.jsx 文件:

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

export default function Document() {
  return (
    <Html lang="zh-CN">
      <Head>
        {/* 这里可以添加全局的 head 元素 */}
      </Head>
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  )
}

关键组件说明

  • <Html>: 包裹整个文档的根元素,可以设置 lang 等属性
  • <Head>: 用于放置文档头部元素(不同于 next/head
  • <Main>: Next.js 页面内容的渲染位置
  • <NextScript>: Next.js 所需脚本的注入位置

重要注意事项

  1. 客户端限制_document 仅在服务器端渲染,不能使用任何客户端特性如 onClick 等事件处理器

  2. Head 组件区别_document 中的 <Head> 不同于 next/head,前者用于全局 head 内容,后者用于页面级 head 内容

  3. 组件限制<Main /> 之外的 React 组件不会被浏览器初始化,不应在此处添加应用逻辑或页面特有样式

  4. 数据获取限制Document 不支持 getStaticPropsgetServerSideProps 等数据获取方法

高级用法:自定义 renderPage

对于需要使用 CSS-in-JS 库等高级场景,可能需要自定义 renderPage 方法:

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
    
    ctx.renderPage = () =>
      originalRenderPage({
        enhanceApp: (App) => App,
        enhanceComponent: (Component) => Component,
      })

    const initialProps = await Document.getInitialProps(ctx)
    return initialProps
  }

  render() {
    return (
      <Html lang="zh-CN">
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}

export default MyDocument

高级用法注意事项

  1. getInitialProps 在客户端路由切换时不会被调用
  2. 此模式主要用于集成 CSS-in-JS 库的 SSR 支持
  3. 对于大多数场景,推荐使用 App Router 而非此高级模式

最佳实践建议

  1. 保持 _document 尽可能简单,仅包含必要的全局文档结构
  2. 页面特有内容应放在页面组件或布局组件中
  3. 对于全局样式,考虑使用 _app 而非 _document
  4. 对于现代项目,优先考虑使用 App Router 而非自定义 _document

通过合理使用自定义 Document,开发者可以更好地控制 Next.js 应用的文档结构,同时保持应用的性能和可维护性。