Featured image of post PPR(部分預先渲染):合併靜態和動態路由Featured image of post PPR(部分預先渲染):合併靜態和動態路由

PPR(部分預先渲染):合併靜態和動態路由

透過 PPR 實現最佳效能,結合 React Suspense 動態注入使用者元素。

問題:靜態與動態的權衡

傳統上,Next.js 開發人員面臨著一個二元選擇:靜態生成(快速但陳舊)或伺服器端渲染(新鮮但較慢)。部分預先渲染(PPR)透過將兩種方法結合在一個頁面中消除了這種權衡——靜態 HTML shell 立即串流傳輸,而動態內容透過 React Suspense 載​​入。

PPR 的工作原理

PPR 的工作原理是使用 React Suspense 識別靜態和動態邊界。在建置期間,Next.js 預先渲染靜態 shell。在請求時,它會用串流動態內容取代 Suspense 回退:

// page.tsx — PPR enabled
import { Suspense } from "react";
import { Header } from "@/components/header";
import { PersonalizedGreeting } from "@/components/greeting";
import { ProductList } from "@/components/products";

export default function HomePage() {
  return (
    <div>
      {/* Static — prerendered at build time */}
      <Header />

      {/* Dynamic — streamed at request time */}
      <Suspense fallback={<GreetingSkeleton />}>
        <PersonalizedGreeting />
      </Suspense>

      {/* Static — prerendered at build time */}
      <ProductList />
    </div>
  );
}

配置

next.config.ts 中啟用 PPR:

// next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  experimental: {
    ppr: true,
  },
};

export default nextConfig;

對於路由層級控制,匯出 experimental_ppr 配置:

// app/page.tsx
export const experimental_ppr = true;

靜態外殼和流邊界

當請求 PPR 頁面時,瀏覽器立即收到:

  1. 靜態 shell — 用於非暫停元件、CSS 和關鍵資源的 HTML
  2. 懸念回退 - 動態內容載入時顯示佔位符 UI
  3. 串流動態內容 — 當每個 Suspense 邊界解析時,其 HTML 會被串流傳輸
Timeline:
Request → Static shell (instant) → Fallback UI shown
        → Dynamic content A arrives → UI updated
        → Dynamic content B arrives → UI updated
        → Page fully interactive

性能優勢

公制固態繼電器靜態PP-R
第一個位元組 (TTFB)慢(伺服器運算)快速(CDN 邊緣)快速(CDN 邊緣)
首次內容繪製 (FCP)
互動時間
動態資料新鮮度新鮮陳舊新鮮
每個請求的伺服器負載最小

使用案例

PPR 非常適合將靜態內容與個人化或即時元素結合的頁面:

電子商務產品頁面:

  • 靜態:產品描述、圖像、評論(已快取)
  • 動態:庫存狀態、價格(特定於使用者)、建議

儀表板應用程式:

  • 靜態:導覽、側邊欄、佈局外殼
  • 動態:用戶特定的指標、通知、即時數據

內容網站:

  • 靜態:文章正文、元資料、SEO 標籤
  • 動態:使用者評論、相關文章(個人化)、訂閱狀態
// Product page with PPR
export default function ProductPage({ params }: { params: { id: string } }) {
  return (
    <>
      {/* Static — cached at edge */}
      <ProductImages id={params.id} />
      <ProductDescription id={params.id} />

      {/* Dynamic — streamed per user */}
      <Suspense fallback={<PriceSkeleton />}>
        <UserSpecificPrice id={params.id} />
      </Suspense>

      <Suspense fallback={<RecommendationsSkeleton />}>
        <PersonalizedRecommendations id={params.id} />
      </Suspense>
    </>
  );
}

搜尋引擎優化的影響

PPR 頁面完全可索引,因為靜態 shell 包含所有 SEO 關鍵內容。動態部分逐漸增強,但搜尋引擎爬蟲接收完整的靜態內容。

  • 元標籤:完全預先渲染
  • 開放圖影像:靜態
  • 主要內容:靜態,動態增強
  • 結構化資料:包含在靜態 shell 中

PPR 與其他渲染策略

戰略建置時間請求時間邊緣快取
靜態(SSG)所有頁面什麼都沒有整頁
固態繼電器什麼都沒有整個頁面按請求
情監偵大多數頁面重新驗證整頁(重新驗證時陳舊)
PP-R靜態外殼動態邊界Shell + 串流媒體

結論

部分預渲染代表了我們對渲染策略的思考方式的根本轉變。 PPR 沒有在靜態速度和動態新鮮度之間進行選擇,而是為我們提供了兩者。透過將動態內容包裝在 Suspense 邊界中,開發人員可以提供即時靜態 shell,同時保持個人化功能的即時互動性。隨著採用率的成長,PPR 很可能成為 Next.js 應用程式中的預設渲染策略。