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 应用程序中的默认渲染策略。