靜態網站生成 (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].js)中 export 一個名為 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 快取,但預渲染的頁面始終是最新的。我們將在下面討論這種方法。

On this page