跳到主要内容

静态站点生成(SSG)

示例

如果页面使用静态生成,页面 HTML 将在构建时生成。这意味着在生产环境中,当你运行 next build 时会生成页面 HTML。然后这个 HTML 将在每次请求时被重用。它可以被 CDN 缓存。

在 Next.js 中,你可以有数据或无数据地静态生成页面。让我们看看每种情况。

无数据的静态生成

默认情况下,Next.js 使用静态生成预渲染页面,无需获取数据。以下是一个示例:

function About() {
return <div>About</div>
}

export default About

请注意,此页面不需要获取任何外部数据即可预渲染。在这种情况下,Next.js 会在构建时为每个页面生成一个 HTML 文件。

有数据的静态生成

某些页面需要获取外部数据才能进行预渲染。有两种情况,可能适用其中一种或两种。在每种情况下,你都可以使用 Next.js 提供的这些函数:

  1. 你的页面内容依赖于外部数据:使用 getStaticProps
  2. 你的页面路径依赖于外部数据:使用 getStaticPaths(通常与 getStaticProps 一起使用)。

场景 1:你的页面内容依赖于外部数据

示例:你的博客页面可能需要从 CMS(内容管理系统)获取博客文章列表。

// TODO: 在此页面可以预渲染之前,需要获取 `posts`(通过调用某个 API 端点)
export default function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li>{post.title}</li>
))}
</ul>
)
}

要在预渲染时获取这些数据,Next.js 允许你从同一文件 export 一个名为 getStaticPropsasync 函数。此函数在构建时被调用,并允许你在预渲染时将获取的数据传递给页面的 props

export default function Blog({ posts }) {
// 渲染文章...
}

// 此函数在构建时被调用
export async function getStaticProps() {
// 调用外部 API 端点来获取文章
const res = await fetch('https://.../posts')
const posts = await res.json()

// 通过返回 { props: { posts } },Blog 组件
// 将在构建时接收 `posts` 作为 prop
return {
props: {
posts,
},
}
}

要了解更多关于 getStaticProps 工作原理的信息,请查看数据获取文档

场景 2:你的页面路径依赖于外部数据

Next.js 允许你创建具有动态路由的页面。例如,你可以创建一个名为 pages/posts/[id].js 的文件来根据 id 显示单个博客文章。这将允许你在访问 posts/1 时显示 id: 1 的博客文章。

要了解更多关于动态路由的信息,请查看动态路由文档

但是,你希望在构建时预渲染哪个 id 可能取决于外部数据。

示例:假设你只向数据库添加了一篇博客文章(id: 1)。在这种情况下,你只想在构建时预渲染 posts/1

稍后,你可能会添加 id: 2 的第二篇文章。然后你也想预渲染 posts/2

因此,预渲染的页面路径取决于外部数据。为了处理这个问题,Next.js 允许你从动态页面(在本例中为 pages/posts/[id].jsexport 一个名为 getStaticPathsasync 函数。此函数在构建时被调用,并允许你指定要预渲染哪些路径。

// 此函数在构建时被调用
export async function getStaticPaths() {
// 调用外部 API 端点来获取文章
const res = await fetch('https://.../posts')
const posts = await res.json()

// 根据文章获取我们想要预渲染的路径
const paths = posts.map((post) => ({
params: { id: post.id },
}))

// 我们将仅在构建时预渲染这些路径。
// { fallback: false } 表示其他路由应该返回 404。
return { paths, fallback: false }
}

同样在 pages/posts/[id].js 中,你需要导出 getStaticProps,以便你可以获取具有此 id 的文章数据并使用它来预渲染页面:

export default function Post({ post }) {
// 渲染文章...
}

export async function getStaticPaths() {
// ...
}

// 此函数也在构建时被调用
export async function getStaticProps({ params }) {
// params 包含文章的 `id`。
// 如果路由像 /posts/1,那么 params.id 就是 1
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()

// 通过 props 将文章数据传递给页面
return { props: { post } }
}

要了解更多关于 getStaticPaths 工作原理的信息,请查看数据获取文档

何时应该使用静态生成?

我们建议尽可能使用静态生成(有数据或无数据),因为你的页面可以构建一次并由 CDN 提供服务,这比让服务器在每次请求时渲染页面要快得多。

你可以将静态生成用于多种类型的页面,包括:

  • 营销页面
  • 博客文章和作品集
  • 电子商务产品列表
  • 帮助和文档

你应该问自己:"我能否在用户请求之前预渲染此页面?"如果答案是肯定的,那么你应该选择静态生成。

另一方面,如果你无法在用户请求之前预渲染页面,静态生成不是一个好主意。也许你的页面显示频繁更新的数据,并且页面内容在每次请求时都会改变。

在这种情况下,你可以执行以下操作之一:

  • 使用静态生成配合客户端数据获取:你可以跳过页面某些部分的预渲染,然后使用客户端 JavaScript 填充它们。要了解更多关于这种方法的信息,请查看数据获取文档
  • 使用服务端渲染:Next.js 在每次请求时预渲染页面。它会更慢,因为页面无法被 CDN 缓存,但预渲染的页面将始终是最新的。我们将在下面讨论这种方法。