[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 都會回傳同一個檔案。 |
getServerSideProps | getStaticProps |
資料在 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:
但 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 會像這樣:
當時間在 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 掉。