跳到内容
构建您的应用程序渲染静态站点生成 (SSG)

静态站点生成 (SSG)

示例

如果页面使用静态生成,则页面 HTML 在构建时生成。这意味着在生产环境中,页面 HTML 在您运行 next build 时生成。此 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: Need to fetch `posts` (by calling some API endpoint)
//       before this page can be pre-rendered.
export default function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}

要在预渲染时获取此数据,Next.js 允许您从同一文件导出一个名为getStaticProps异步函数。此函数在构建时被调用,并允许您在预渲染时将获取的数据传递给页面的props

export default function Blog({ posts }) {
  // Render posts...
}
 
// This function gets called at build time
export async function getStaticProps() {
  // Call an external API endpoint to get posts
  const res = await fetch('https://.../posts')
  const posts = await res.json()
 
  // By returning { props: { posts } }, the Blog component
  // will receive `posts` as a prop at build time
  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].js导出一个名为 getStaticPaths异步函数。此函数在构建时被调用,并允许您指定要预渲染的路径。

// This function gets called at build time
export async function getStaticPaths() {
  // Call an external API endpoint to get posts
  const res = await fetch('https://.../posts')
  const posts = await res.json()
 
  // Get the paths we want to pre-render based on posts
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))
 
  // We'll pre-render only these paths at build time.
  // { fallback: false } means other routes should 404.
  return { paths, fallback: false }
}

同样在 pages/posts/[id].js 中,您需要导出 getStaticProps,以便您可以获取此 id 的文章数据并将其用于预渲染页面

export default function Post({ post }) {
  // Render post...
}
 
export async function getStaticPaths() {
  // ...
}
 
// This also gets called at build time
export async function getStaticProps({ params }) {
  // params contains the post `id`.
  // If the route is like /posts/1, then params.id is 1
  const res = await fetch(`https://.../posts/${params.id}`)
  const post = await res.json()
 
  // Pass post data to the page via props
  return { props: { post } }
}

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

何时应使用静态生成?

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

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

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

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

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

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

  • 使用带客户端数据获取的静态生成:您可以跳过预渲染页面的一部分,然后使用客户端 JavaScript 填充它们。要了解有关此方法的更多信息,请查阅数据获取文档
  • 使用服务器端渲染:Next.js 在每个请求时预渲染页面。这会比较慢,因为页面不能由 CDN 缓存,但预渲染的页面将始终是最新的。我们将在下面讨论这种方法。