← 返回渲染测试

部分预渲染 (PPR) 🧪 实验性

🧪 什么是 PPR?

Partial Prerendering(PPR)是 Next.js 的一个实验性特性, 它允许在同一个页面中混合静态渲染动态渲染

核心概念:

  • Shell(壳):静态部分,构建时生成
  • Holes(洞):动态部分,请求时渲染
  • 使用 Suspense 边界定义 Holes
  • 结合了 SSG 的速度和 SSR 的灵活性
  • 目前处于实验阶段(Next.js 15+)

⚙️ 如何启用 PPR?

PPR 是实验性特性,需要在 next.config.ts 中启用:

// next.config.ts
const nextConfig = {
  experimental: {
    ppr: true,
  },
};

export default nextConfig;

⚠️ 警告:PPR 仍在实验阶段,API 可能会变化,不建议在生产环境使用。

📦 静态 Shell(构建时生成)

这部分内容在构建时生成,所有用户看到相同的内容。

构建时间:2025-12-17T09:54:12.774Z

✅ 多次刷新页面,这个时间保持不变

🕳️ 动态 Holes(请求时渲染)

动态内容(Hole)

这部分在请求时渲染,每次访问都会更新

渲染时间:2025-12-17T09:54:12.775Z

✅ 每次刷新都会变化

动态内容(Hole)

这部分在请求时渲染,每次访问都会更新

渲染时间:2025-12-17T09:54:12.775Z

✅ 每次刷新都会变化

🔍 PPR 工作原理

1️⃣ 构建时

  • Next.js 生成静态 Shell(页面的静态部分)
  • 标记 Suspense 边界作为 Holes(动态部分)
  • Shell 被缓存,可以立即响应

2️⃣ 请求时

  • 立即返回静态 Shell(TTFB 快)
  • 服务器渲染 Holes 中的动态内容
  • 动态内容通过 Streaming 发送

3️⃣ 用户体验

  • 用户立即看到页面结构(Shell)
  • 动态部分显示 loading 状态
  • 动态内容加载完成后替换 loading

🧪 如何验证 PPR?

  1. 启用 PPR:

    next.config.ts 中添加 experimental.ppr: true

  2. 构建项目:
    pnpm build

    构建日志中会显示使用 PPR 的页面

  3. 观察行为:

    - 静态 Shell 的构建时间不变
    - 动态 Holes 的渲染时间每次都变化

  4. 查看 Network:

    页面首先返回 Shell HTML,然后通过 Streaming 更新 Holes

💡 适用场景

✅ 最适合

  • 电商产品页(静态信息 + 动态库存)
  • 个人主页(静态布局 + 动态用户数据)
  • 博客文章(静态内容 + 动态评论)
  • 仪表盘(静态框架 + 动态图表)

❌ 不适合

  • 完全静态的页面(用 SSG)
  • 完全动态的页面(用 SSR)
  • 生产环境(仍在实验阶段)

💻 代码示例

// app/product/[id]/page.tsx
import { Suspense } from 'react';

// 动态组件 - Hole
async function DynamicStock({ productId }) {
  const stock = await fetchStock(productId); // 实时库存
  return <div>库存:{stock}</div>;
}

export default async function ProductPage({ params }) {
  // 静态内容 - Shell
  const product = await fetchProduct(params.id);
  
  return (
    <div>
      {/* Shell:静态部分 */}
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      <img src={product.image} alt={product.name} />
      
      {/* Hole:动态部分 */}
      <Suspense fallback={<div>Loading stock...</div>}>
        <DynamicStock productId={params.id} />
      </Suspense>
    </div>
  );
}

⚖️ 优缺点

✅ 优点

  • 性能最优:结合 SSG 和 SSR 的优点
  • TTFB 快:Shell 立即返回
  • 灵活性高:页面不同部分可以用不同策略
  • SEO 友好:Shell 是完整的 HTML

❌ 缺点

  • 实验性:API 可能变化,不稳定
  • 复杂度高:需要规划 Shell 和 Holes
  • 需要 Suspense:增加代码复杂度
  • 浏览器支持:需要现代浏览器