跳至主要内容

[NextDoc] Basic Feature 閱讀筆記

非原創文章,內容整理自: Basic Features @ Next.js Docs

Pages

預設的情況下,Next.js 會 pre-render 所有頁面,也就是會針對每個頁面預先產生 HTML,而不是都靠 client-side JavaScript 來產生頁面。

每一個產生的 HTML 都會帶有少部分必須用到的 JavaScript 程式碼,當瀏覽器載入這個頁面時,這些 JavaScript 的程式碼就會執行,以確保該頁面可以保有原本互動的功能,而這個過程就稱作 hydration

提示

在 Next.js 中,pre-render 指的是預先將 HTML 頁面產出來的意思。

在 Next.js 中有兩種形式的 pre-render(也就是會預先產出 HTML 頁面):

  • Static Generation (SSG):HTML 頁面 build 好後,每次收到 request 時就重複使用。
  • Server-side Rendering(SSR):HTML 會在每次收到 request 時被 server 產生。
提示

精確來說,SSG 的 HTML 頁面是在 Next.js 的 build time(即,執行 npm run build 時)就被建立起來。

Server-side Rendering (SSR)Static Site Generation (SSG)
HTML 是在收到 request 時才由 server 產生。build time 就把 HTML 頁面建立好,每次收到 request 都會回傳同一個檔案。
getServerSidePropsgetStaticProps
資料在 server 收到 request 後才去拉取,pre-render 時才把資料放入 HTML。又稱 Dynamic Rendering資料在 build time 時就取得,並放入 HTML 頁面

Data Fetching

:::參考資料

Data Fetching @ Nest.js

:::

getStaticProps

fallback

若在 getStaticProps 中回傳 fallback: true 時,next.js 不會在 build time 時就把該靜態頁面產生,而是當有使用者第一次對該頁面發送請求時,使用者會先看到 Fallback Page,並會開始建立靜態頁面,靜態頁面建立好後,後續其他的使用者都可以直接取用該靜態頁面。

這適合用在有非常大量的靜態頁面要產生時(例如商品頁),若在 build time 就要把所有的頁面都產出來會耗費非常久的時間,此時可以搭配 fallback: true 使用。

notFound: true

getStaticProps 中如果 return { notFound: true } 的話,使用者會被轉址到 404 Not Found 頁面。

getStaticPaths

fallback(經常搭配 ISR 使用)

可以參考官方文件看使用時機

fallback: false 時,路由不存在就會出現 404 Not Found 的頁面。

fallback: 'blocking' 時,路由不存在時,依然會呼叫 getStaticProps 並產生新的對應的路由。然而,在呼叫 getStaticProps 時如果拿不到對應的資料(例如,該筆 id 不存在),有可能會顯示 500 Internal Server Error,因此記得要在 getStaticProps 中做對應的 error handling。

Incremental Static Regeneration (ISR)

Next.js 的 Incremental Static Regeneration 是參考 stale-while-revalidate 的想法加以實作。

ISR 的一個重點是「當 cache 過期後,使用者第一次發出請求時,伺服器會先回傳前次的 cache,並「同時」觸發新頁面的產生,下次再發送請求時,就可以取得新 build 好的頁面,因此不會有需要等待 server 處理完才能得到回應的情況,大幅減少從伺服器取得回應的時間」。

也因為 ISR 在 Cache 過期後會重 build 該頁面(而非整個專案),因此還可以在不需要重新 build 整個專案的情況下,可以達到靜態頁面的更新**。

預設的情況下,Next.js 的 SSG 會 cache 一年:

Cache-Control: s-maxage=31536000, stale-while-revalidate

也就是說,瀏覽器向伺服器發送請求時,伺服器都會回傳 304 Not Modified:

Nextjs Cache Control

但 Next.js 提供了另一種「類似」於 stale-while-revalidate 的方式,可以設定一段時間:

export async function getStaticProps() {
return {
props: {
posts,
},
// Next.js will attempt to re-generate the page:
// - When a request comes in
// - At most once every second
revalidate: 59, // in 59 seconds
};
}

此時的 Cache Control 會像這樣:

Nextjs Cache Control

當時間在 59 秒以內時,伺服器會直接回傳 304,但若超過 59 秒後,再次向伺服器發送請求時,伺服器會先以 cache 的內容當作回應,但同時檢查有無更新的資料(觸發 getStaticProps 中的方法),若有,使用者再下次的請求發送時,使用者就會看到最新的內容。

關於字典檔的替換(i18n)

雖然 ISR 會在超過設定的時間和就重新產生新的頁面,但如果字典檔在這段時間內有變更的話, next-18next 並不會重新讀取放在 public/locales 資料夾中的字典檔,而是需要重新啟動伺服器(npm start)才會在重新載入新的字典檔。

根據測試,假設設定的是 revalidate: 10 的話:

  • 第一次啟動伺服器後,若字典檔內的文字有變更,因為 next-18next 不會重新吃字典檔,因此即使過了 revalidate 的時間,且頁面重新產生,但仍不會顯示更新後的文字。
  • 需要重新啟動伺服器,next-i18next 才會吃到新的字典檔。
  • 重新啟動伺服器後
    • 伺服器「第一次收到請求時」開始計時
    • 開始計時後的 10 秒內(因為 revalidate 時間設為 10)向伺服器發送請求,都會先以舊有的 cache 做回應,不會看到新的字典檔
    • 10 秒後發送的請求會觸發畫面重新產生,這時候 server 會根據新吃到的字典檔來產生畫面
    • 再發送一次請求時才會看到最新的內容

Environment Variables (ENV)

在 TypeScript 中,除了可以使用 .env(套用到所有環境)、.env.development.env.production 之外,還有一個是 .env.local,這個 .env.local 能夠覆蓋掉所有上述的設定,是實際上放置「密碼」檔案。

也就是說,.env.env.development.env.production放的算是「預設值」,它們都可以被 git 紀錄,但是 .env.local 應該要被 gitignore 掉。