PPR(Partial Prerendering)是Next.js 14引入的實驗性功能,他可以讓頁面中需動態資料的部分以streaming方式載入,而其餘部分能夠保持Static Rendering。
以往我們通常會將不容易變動的頁面做成靜態渲染,例如部落格網站的文章內容通常不會頻繁更動,因此不需要每次都重新向server發送文章的請求。這麼做可以減少next.js server端的負擔,也可以使用戶得以更迅速的看到頁面。
然而在實作上有可能在頁面上使用了Dynamic API而破壞了我們原本期望的靜態渲染。
Dynamic API 指的是會根據 request 狀態(cookies、headers、searchParams 等)動態產生內容的 API,這些 API 在編譯時期無法預先渲染,因此會讓整個頁面被標記為 Dynamic Rendering。
下圖為官方文檔截圖:
可以看到cookies
也是其中一員,這邊舉一個常見的例子:假設網頁全站使用的Header組件使用到了cookies
來進行身份驗證,這將導致全站都被迫轉為Dynamic Rendering,即使95%的內容是靜態的。
如果使用了第三方的Auth例如Clerk等服務,他們的組件內大多也是用了Dynamic API,因此會有相同的狀況。
執行npm run build
可以發現路由被標記成dynamic。
遇到這類問題通常會改用client component,然而改成client component會增加bundle體積,且有時會需要連實作方式都一併調整例如重新撰寫fetch資料邏輯,造成額外的工作,此時就顯現出PPR這個新feature的方便之處了。
不過有幾點需要注意:
canary
版本的next.js,並且該功能是針對app router。npm install next@canary
// next.config.ts
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
ppr: 'incremental',
},
}
export default nextConfig
之後在需要啟用的route上方添加:
// app/[your_route]/page.tsx
export const experimental_ppr = true
- experimental_ppr will apply to all children of the route segment, including nested layouts and pages. You don't have to add it to every file, only the top segment of a route.
- To disable PPR for children segments, you can set experimental_ppr to false in the child segment.
之後只需使用react Suspense
將Dynamic component包起來就好了,使用方式非常的簡單,以下附上官網範例。
import { Suspense } from 'react'
import StaticComponent from './StaticComponent'
import DynamicComponent from './DynamicComponent'
import Fallback from './Fallback'
export const experimental_ppr = true
export default function Page() {
return (
<>
<StaticComponent />
<Suspense fallback={<Fallback />}>
<DynamicComponent />
</Suspense>
</>
)
}
這時我們再執行build就可以看到該route從Dynamic變成PPR囉。
PPR 的出現,讓我們可以同時保有靜態渲染的好處,又能在需要的地方動態載入資料,並透過 Streaming 讓使用者幾乎感覺不到延遲。 隨著這項功能成熟,說不定未來會成為Next.js預設的渲染模式唷。