5 分鐘理解 Next.js Static Export

趙康發表於2023-09-27

5 分鐘理解 Next.js Static Export

在本篇文章中,我們將介紹:

  • Next.js 中的 Static Export 功能,以及它是如何工作的;
  • 在 Next.js 中如何使用 Server Components 和 Client Components 來實現不同的資料獲取策略;
  • 一些相關的基本概念。

什麼是 Static Export

Static Export 是一種 Web 開發模式,它允許我們在構建網站時將頁面提前生成為靜態 HTML 檔案,而不是在每次請求時動態生成。這意味著頁面內容在構建時就已經準備好,而不是等待使用者請求時才生成。這樣做的好處是:

  • 和 SSR(Server Side Rendering) 相比,可以提高網站的效能和降低網站託管成本:因為頁面主要內容可以直接從靜態檔案中提供,而無需進行伺服器端渲染;
  • 和 SPA(Single Page Application)相比,有利於SEO且有更好的首屏載入效能:因為作為網頁骨架的 Server Components 是在構建時渲染的,只有少量的 Client Components 點綴其中。這也會進一步降低 Static Export 構建出的 JS bundle 大小。

什麼是靜態網站

靜態網站是一種最原始的 Web 形式,它由靜態檔案組成。和 JSP/Blade/Pug 等後端模板引擎不同, 它不需要伺服器端程式碼來生成頁面內容(拼接 HTML)。一個簡單的靜態網站可以透過將HTML、CSS和JavaScript等檔案放入靜態伺服器中或者本地檔案系統中,透過瀏覽器進行訪問。

Server Components

在 Next.js 中,元件預設被視為 Server Components。Server Components 在 Static Export 時可以生成靜態頁面。讓我們看一個示例:

function Home() {
  return (
    <main>
      <ComponentA />
    </main>
  );
}
async function ComponentA() {
  const data = await fetchData(
    '/some_data_that_rarely_changes_so_we_fetch_when_building'
  );

  return <div className='component-a'>{data}</div>;
}

在 Static Export 構建時,上述程式碼會生成如下的HTML:

<main>
  <div className='component-a'>
    some data that rarely changes
  </div>
</main>

這意味著資料在構建時就被獲取,並且在每個使用者請求頁面時都是相同的。

Client Components

但如果我們希望在每次使用者訪問頁面或與頁面互動時獲取新資料,就需要使用 Client Components。以下是一個示例:

'use client';
// ...
export function ComponentB() {
  const [count, setCount] = useState(0);
  const [data, setData] = useState();
  useEffect(() => {
    fetchData(
      `/some_frequently_changing_data_so_we_fetch_every_time_user_open_the_page_or_click_the_button?param=${count}`
    ).then(setData);
  }, [count]);

  return (
    <div className='component-b'>
      <div className='count'>{count}</div>
      <button onClick={() => setCount((val) => val + 1)}>add</button>
      <div className='data'>{data}</div>
    </div>
  );
}
function Home() {
  return (
    <main>
      <ComponentA />
      <ComponentB />
    </main>
  );
}

在 Static Export 構建時,上述程式碼會生成如下的HTML:

<main>
  <div className='component-a'>
    some data that rarely changes
  </div>
  <div className='component-b'>
    <div className='count'>0</div>
    <button>add</button>
    <div className='data'></div>
  </div>
</main>

這裡的關鍵區別在於:

  • some_data_that_rarely_changes 在構建時就被獲取;
  • some_frequently_changing_data 只有在使用者開啟頁面且水合(Hydration)完成之後才會獲取,或點選 "add" 按鈕後才會獲取,而不是在構建時就提前獲取。

而傳統的 SPA(Single Page Application),在構建後,通常你只會得一個空空如也的HTML:

<div id='root'></div>
<script src="app.js" />

在 app.js 下載和執行完成之前,使用者只能面對一個空白的網頁。

總結

在 Next.js 中,Static Export 是一種強大的工具,它允許我們在構建時生成靜態頁面,從而提高效能和載入速度,且有更好的 SEO。透過 Server Components 和 Client Components,我們可以選擇何時獲取資料,以滿足不同的需求。使用這些工具,你可以更靈活地構建出適應不同場景的網站。

相關文章