跳到內容
構建您的應用程式渲染靜態站點生成 (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 快取,但預渲染的頁面將始終是最新的。我們將在下面討論這種方法。