Skip to main content

静态站点生成 (SSG)

Examples

如果页面使用静态生成,则页面 HTML 是在构建时生成的。这意味着在生产中,页面 HTML 是在运行 next build 时生成的。然后,该 HTML 将在每个请求中重复使用。它可以由 CDN 缓存。

¥If a page uses Static Generation, the page HTML is generated at build time. That means in production, the page HTML is generated when you run next build. This HTML will then be reused on each request. It can be cached by a CDN.

在 Next.js 中,你可以静态生成包含或不包含数据的页面。让我们看一下每个案例。

¥In Next.js, you can statically generate pages with or without data. Let's take a look at each case.

无数据静态生成

¥Static Generation without data

默认情况下,Next.js 使用静态生成预渲染页面,而不获取数据。这是一个例子:

¥By default, Next.js pre-renders pages using Static Generation without fetching data. Here's an example:

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

export default About

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

¥Note that this page does not need to fetch any external data to be pre-rendered. In cases like this, Next.js generates a single HTML file per page during build time.

带数据的静态生成

¥Static Generation with data

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

¥Some pages require fetching external data for pre-rendering. There are two scenarios, and one or both might apply. In each case, you can use these functions that Next.js provides:

  1. 你的页面内容取决于外部数据:使用 getStaticProps

    ¥Your page content depends on external data: Use getStaticProps.

  2. 你的页面路径取决于外部数据:使用 getStaticPaths(通常除了 getStaticProps 之外)。

    ¥Your page paths depend on external data: Use getStaticPaths (usually in addition to getStaticProps).

场景 1:你的页面内容取决于外部数据

¥Scenario 1: Your page content depends on external data

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

¥Example: Your blog page might need to fetch the list of blog posts from a CMS (content management system).

// 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 允许你从同一文件中 export 一个名为 getStaticPropsasync 函数。该函数在构建时被调用,并允许你在预渲染时将获取的数据传递到页面的 props

¥To fetch this data on pre-render, Next.js allows you to export an async function called getStaticProps from the same file. This function gets called at build time and lets you pass fetched data to the page's props on pre-render.

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 如何工作的更多信息,请查看 数据获取文档

¥To learn more about how getStaticProps works, check out the Data Fetching documentation.

场景 2:你的页面路径取决于外部数据

¥Scenario 2: Your page paths depend on external data

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

¥Next.js allows you to create pages with dynamic routes. For example, you can create a file called pages/posts/[id].js to show a single blog post based on id. This will allow you to show a blog post with id: 1 when you access posts/1.

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

¥To learn more about dynamic routing, check the Dynamic Routing documentation.

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

¥However, which id you want to pre-render at build time might depend on external data.

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

¥Example: suppose that you've only added one blog post (with id: 1) to the database. In this case, you'd only want to pre-render posts/1 at build time.

稍后,你可以添加带有 id: 2 的第二篇文章。那么你也想预渲染 posts/2

¥Later, you might add the second post with id: 2. Then you'd want to pre-render posts/2 as well.

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

¥So your page paths that are pre-rendered depend on external data. To handle this, Next.js lets you export an async function called getStaticPaths from a dynamic page (pages/posts/[id].js in this case). This function gets called at build time and lets you specify which paths you want to pre-render.

// 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 获取有关帖子的数据并使用它来预渲染页面:

¥Also in pages/posts/[id].js, you need to export getStaticProps so that you can fetch the data about the post with this id and use it to pre-render the page:

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 如何工作的更多信息,请查看 数据获取文档

¥To learn more about how getStaticPaths works, check out the Data Fetching documentation.

我什么时候应该使用静态生成?

¥When should I use Static Generation?

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

¥We recommend using Static Generation (with and without data) whenever possible because your page can be built once and served by CDN, which makes it much faster than having a server render the page on every request.

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

¥You can use Static Generation for many types of pages, including:

  • 营销页面

    ¥Marketing pages

  • 博客文章和作品集

    ¥Blog posts and portfolios

  • 电子商务产品列表

    ¥E-commerce product listings

  • 帮助和文档

    ¥Help and documentation

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

¥You should ask yourself: "Can I pre-render this page ahead of a user's request?" If the answer is yes, then you should choose Static Generation.

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

¥On the other hand, Static Generation is not a good idea if you cannot pre-render a page ahead of a user's request. Maybe your page shows frequently updated data, and the page content changes on every request.

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

¥In cases like this, you can do one of the following:

  • 使用静态生成与客户端数据获取:你可以跳过预渲染页面的某些部分,然后使用客户端 JavaScript 来填充它们。要了解有关此方法的更多信息,请查看 数据获取文档

    ¥Use Static Generation with Client-side data fetching: You can skip pre-rendering some parts of a page and then use client-side JavaScript to populate them. To learn more about this approach, check out the Data Fetching documentation.

  • 使用服务器端渲染:Next.js 针对每个请求预渲染一个页面。它会更慢,因为页面无法被 CDN 缓存,但预渲染的页面将始终是最新的。我们将在下面讨论这种方法。

    ¥Use Server-Side Rendering: Next.js pre-renders a page on each request. It will be slower because the page cannot be cached by a CDN, but the pre-rendered page will always be up-to-date. We'll talk about this approach below.