跳到內容
建置您的應用程式轉譯靜態網站產生 (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 允許您從同一個檔案 export 一個名為 getStaticPropsasync 函式。此函式會在建置時期呼叫,並讓您在預先轉譯時將抓取的資料傳遞到頁面的 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].jsexport 一個名為 getStaticPathsasync 函式。此函式會在建置時呼叫,讓您指定想要預先渲染的路徑。

// 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 中,您需要 export 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 快取,但預先渲染的頁面將始終是最新的。我們將在下面討論這種方法。