Skip to content

服务端渲染(SSR)与客户端渲染(CSR) ​

本手册从"页面到底在哪里渲染"这一根本问题出发,梳理传统 SSR、现代同构 SSR、CSR 三种基础范式,再深入 SSG / ISR、React Server Components 等现代衍生方案,最后落到量化对比、选型指南与 Next.js 双 Router 实战,帮助你构建完整的渲染架构知识体系。

导航目录 ​

一、渲染范式篇 ​

二、现代衍生方案篇 ​

三、对比与选型篇 ​

四、框架实战篇 ​


一、传统服务端渲染(SSR) ​

核心概念

传统服务端渲染(SSR) 指由服务器在每次请求时动态拼装出完整 HTML 再返回给浏览器。页面的数据获取、模板渲染全部在服务端完成,浏览器拿到的就是"开箱即用"的完整页面,代表技术有 JSP、PHP、ASP、EJS 等模板引擎。

技术原理 ​

核心流程 ​

  1. 请求处理:用户发起页面请求,服务器接收 HTTP 请求
  2. 数据获取:服务器执行后端逻辑,从数据库或 API 获取数据
  3. 模板渲染:使用模板引擎(JSP、EJS 等)将数据注入 HTML 模板
  4. 响应返回:生成完整的 HTML 文档并返回给客户端
  5. 客户端展示:浏览器直接渲染接收到的静态 HTML

请求流程图:

text
浏览器                    服务器                    数据库/API
   |  1. 发起页面请求        |                          |
   | ──────────────────────►|                          |
   |                        |  2. 查询数据             |
   |                        | ────────────────────────►|
   |                        |     返回数据             |
   |                        | ◄────────────────────────|
   |                        | [3. 模板引擎注入渲染 HTML]|
   |  4. 返回完整 HTML       |                          |
   | ◄──────────────────────|                          |
   | [5. 直接渲染展示,无需等待 JS]                     |

技术实现示例 ​

功能说明:传统服务端渲染的 JSP 实现示例,展示了服务器如何生成动态 HTML。

java
// JSP 示例
<%@ page contentType="text/html;charset=UTF-8" %>
<html>
<head>
    <title>商品列表</title>
</head>
<body>
    <h1>商品列表</h1>
    <%
        List<Product> products = productService.getProducts();
        for(Product product : products) {
    %>
        <div class="product">
            <h2><%= product.getName() %></h2>
            <p>价格: <%= product.getPrice() %></p>
        </div>
    <% } %>
</body>
</html>

优势分析 ​

性能优势 ​

  • 首屏加载快:用户无需等待 JavaScript 下载和执行
  • SEO 友好:搜索引擎爬虫直接获取完整内容
  • 低客户端要求:即使在 JavaScript 禁用情况下也能正常显示

开发优势 ​

  • 技术栈统一:前后端使用相同语言和技术栈
  • 简单直接:开发流程直观,学习曲线平缓

局限性 ​

用户体验问题 ​

  • 页面刷新:每次导航都需要完整页面重载
  • 交互延迟:简单的交互也需要与服务器通信
  • 状态丢失:页面跳转时客户端状态无法保持

开发维护挑战 ​

  • 代码耦合:业务逻辑与展示逻辑紧密绑定
  • 分工模糊:前端后端开发职责界限不清晰
  • 技术债务:随着项目扩大,维护成本指数级增长

优劣一览 ​

优势 ✅局限性 ❌
首屏快,无需等待 JS 下载执行每次导航都整页刷新,交互体验差
SEO 友好,爬虫直接拿到内容简单交互也要往返服务器,延迟高
JS 禁用也能显示,低客户端要求跳转丢失客户端状态
前后端技术栈统一,学习曲线平缓业务与展示逻辑耦合,维护成本高

演进方向

传统 SSR 的痛点在于"每次交互都回服务器"。为了兼顾 SSR 的首屏 / SEO 优势与 SPA 的流畅交互,才诞生了下一节的同构渲染——同一套组件代码在服务端与客户端各跑一次。


二、现代服务端渲染(同构渲染) ​

核心概念

同构渲染(Isomorphic / Universal Rendering) 指同一套组件代码既能在服务端运行生成首屏 HTML,又能在客户端"注水"接管交互。它把传统 SSR 的首屏优势与 CSR 的流畅交互结合起来,是现代 SSR 框架(Next.js / Nuxt.js)的技术基石。

架构设计 ​

同构渲染核心概念 ​

功能说明:展示同构渲染的完整流程,包括服务端渲染和客户端注水两个阶段。

javascript
// 服务端渲染
// server.js
import { renderToString } from "react-dom/server";
import App from "./App";

app.get("/", (req, res) => {
  const html = renderToString(<App />);
  res.send(`
        <html>
            <head><title>同构应用</title></head>
            <body>
                <div id="root">${html}</div>
                <script src="/client.js"></script>
            </body>
        </html>
    `);
});

// 客户端注水
// client.js
import { hydrateRoot } from "react-dom/client";
import App from "./App";

hydrateRoot(document.getElementById("root"), <App />);

关键技术流程 ​

  1. 服务端渲染阶段

    • 执行 React/Vue 组件渲染
    • 处理数据获取和状态初始化
    • 生成静态 HTML 字符串
  2. 客户端注水阶段

    • 复用服务端渲染的 DOM 结构
    • 绑定事件处理器和交互逻辑
    • 接管后续的路由和状态管理

同构渲染时序图:

text
浏览器                                SSR 服务器
   |  请求页面                          |
   | ─────────────────────────────────►|
   |     [renderToString 生成 HTML]     |
   |  返回带内容的 HTML(首屏可见)     |
   | ◄─────────────────────────────────|
   |  [展示静态 HTML,此时不可交互]     |
   |  下载 client.js                    |
   | ─────────────────────────────────►|
   |     返回 JS bundle                 |
   | ◄─────────────────────────────────|
   |  [hydrateRoot 注水:复用 DOM+绑事件]|
   |  [页面变为可交互(TTI)]           |

首屏可见(FCP) 在 HTML 返回时即达成,但 可交互(TTI) 要等 JS 下载并注水完成,两者之间存在一段「可见但点不动」的窗口期。

水合不匹配(Hydration Mismatch) ​

什么是水合不匹配

注水时 React 会比对客户端首次渲染结果与服务端返回的 HTML,若两者不一致就会报 hydration 警告并丢弃服务端 DOM 重新渲染,导致闪烁与性能损耗,是同构 SSR 最高频的坑。

常见原因:

  • 使用了 Date.now()、Math.random() 等服务端/客户端结果不同的值
  • 直接读取 window、localStorage 等浏览器专属 API
  • 服务端与客户端的数据源/状态不一致
  • HTML 结构非法嵌套(如 <p> 里放 <div>)被浏览器自动纠正
javascript
// ❌ 错误:服务端与客户端渲染结果不同
function Bad() {
  return <div>{Date.now()}</div>;
}

// ✅ 正确:把浏览器相关逻辑放到 useEffect(仅客户端执行)
function Good() {
  const [time, setTime] = useState(null);
  useEffect(() => {
    setTime(Date.now());
  }, []);
  return <div>{time}</div>;
}

性能优化策略 ​

缓存机制 ​

功能说明:实现页面级缓存,减少重复渲染,提高服务端渲染性能。

javascript
// 页面级缓存示例
const microCache = new Map();

app.get("*", (req, res) => {
  const cacheKey = req.url;

  // 检查缓存
  if (microCache.has(cacheKey)) {
    return res.send(microCache.get(cacheKey));
  }

  // 渲染页面
  const html = renderToString(<App />);

  // 设置缓存(2分钟过期)
  microCache.set(cacheKey, html);
  setTimeout(() => microCache.delete(cacheKey), 120000);

  res.send(html);
});

流式渲染优化 ​

功能说明:使用 React 18 的流式渲染功能,实现页面内容的渐进式加载,提升用户体验。

javascript
// React 18 流式渲染
import { renderToPipeableStream } from "react-dom/server";

app.use("*", (request, response) => {
  const { pipe } = renderToPipeableStream(<App />, {
    bootstrapScripts: ["/main.js"],
    onShellReady() {
      response.setHeader("content-type", "text/html");
      pipe(response);
    },
  });
});

技术挑战与解决方案 ​

环境适配问题 ​

功能说明:解决服务端和客户端环境差异问题,实现跨环境兼容的数据获取和 API 调用。

javascript
// 环境检测与适配
const isServer = typeof window === "undefined";

// 条件性导入浏览器相关API
if (!isServer) {
  const { animationFrame } = require("./browser-apis");
}

// 数据获取适配
class DataFetcher {
  static async fetchData() {
    if (isServer) {
      // 服务端直接调用API
      return await database.query();
    } else {
      // 客户端通过HTTP请求
      return await fetch("/api/data").then((r) => r.json());
    }
  }
}

三、客户端渲染(CSR) ​

核心概念

客户端渲染(CSR) 指服务器只返回一个几乎空白的 HTML 外壳(仅含一个 #root 挂载点和 JS 引用),页面的 DOM 结构、数据获取与渲染全部由浏览器执行 JavaScript 完成。这是 React / Vue 单页应用(SPA)的默认工作方式。

架构演进 ​

单页面应用(SPA)架构 ​

text
应用结构:
- index.html (入口文件)
- bundle.js (应用代码包)
- 路由管理 (React Router, Vue Router)
- 状态管理 (Redux, Vuex)
- API通信层 (RESTful/GraphQL)

CSR 加载流程图:

text
浏览器                          服务器 / API
   |  1. 请求页面                    |
   | ─────────────────────────────► | 服务器
   |  2. 返回空壳 HTML(仅 root)    |
   | ◄───────────────────────────── |
   |  3. 下载 bundle.js             |
   | ─────────────────────────────► | 服务器
   |     返回 JS                     |
   | ◄───────────────────────────── |
   |  4. 执行 JS,渲染组件(白屏结束)|
   |  5. 请求数据                    |
   | ─────────────────────────────► | API 服务
   |     返回数据                    |
   | ◄───────────────────────────── |
   |  6. 数据渲染,页面完整可交互    |

CSR 首屏需经历「空壳 → 下载 JS → 执行渲染 → 请求数据」多个串行阶段,因此首屏较慢且爬虫拿到的是空壳 HTML(SEO 弱)。

现代 CSR 技术栈 ​

功能说明:展示现代客户端渲染的完整技术栈,包括路由管理、状态管理和组件渲染。

javascript
// React SPA 示例
import { createRoot } from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import { Provider } from "react-redux";
import App from "./App";
import store from "./store";

const container = document.getElementById("root");
const root = createRoot(container);

root.render(
  <Provider store={store}>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </Provider>
);

性能优化技术 ​

代码分割与懒加载 ​

功能说明:使用 React.lazy 实现路由级代码分割,减少初始加载体积,提升应用性能。

javascript
// React.lazy 实现路由级代码分割
import { lazy, Suspense } from "react";

const Home = lazy(() => import("./components/Home"));
const About = lazy(() => import("./components/About"));

function App() {
  return (
    <Suspense fallback={<div>加载中...</div>}>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </Suspense>
  );
}

资源预加载策略 ​

功能说明:通过预加载关键资源和数据,提升页面加载速度和用户体验。

html
<!-- 关键资源预加载 -->
<link rel="preload" href="/critical.css" as="style" />
<link rel="preload" href="/main.js" as="script" />
<link rel="prefetch" href="/about-bundle.js" as="script" />

<!-- 数据预获取 -->
<script>
  // 预获取下一页数据
  if (isHighSpeedNetwork()) {
    fetch("/api/next-page-data").then(() => {
      // 缓存数据供后续使用
    });
  }
</script>

SEO 优化方案 ​

预渲染技术 ​

功能说明:使用 Puppeteer 实现页面预渲染,提高 CSR 应用的 SEO 友好度。

javascript
// 使用Puppeteer进行预渲染
const puppeteer = require("puppeteer");

async function prerenderPage(url, outputPath) {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();

  // 设置用户代理为Googlebot
  await page.setUserAgent("Googlebot/2.1");

  await page.goto(url, { waitUntil: "networkidle0" });
  const html = await page.content();

  fs.writeFileSync(outputPath, html);
  await browser.close();
}

动态元标签管理 ​

功能说明:使用 React Helmet 动态管理页面元标签,提升 CSR 应用的 SEO 效果。

javascript
// React Helmet 示例
import { Helmet } from "react-helmet";

function ProductPage({ product }) {
  return (
    <div>
      <Helmet>
        <title>{product.name} - 我的商店</title>
        <meta name="description" content={product.description} />
        <meta property="og:title" content={product.name} />
        <meta property="og:description" content={product.description} />
      </Helmet>

      <h1>{product.name}</h1>
      <p>{product.description}</p>
    </div>
  );
}

四、静态生成 SSG 与增量再生 ISR ​

核心概念

SSG(Static Site Generation,静态站点生成) 在构建时就把页面渲染成静态 HTML,请求到来时直接返回、无需服务端实时计算,性能与 SSR 首屏相当却几乎零服务器成本。 ISR(Incremental Static Regeneration,增量静态再生) 是 Next.js 对 SSG 的增强:静态页面可以在后台按时间间隔或按需重新生成,兼顾静态性能与内容新鲜度。

SSG 与 ISR 的关系 ​

text
构建时 build ──(预渲染)──► 静态 HTML 文件 ──(CDN 分发)──► 用户请求直接命中
                              ▲                              │
                              │            ┌─────────────────┤
     (ISR revalidate 到期)    │            │  SSG:内容永久静态 → 需重新构建才更新
   后台再生新 HTML ─(悄悄替换)─┘            └  ISR:到期后台再生新 HTML

Next.js SSG 实现(Page Router) ​

功能说明:getStaticProps 在构建时执行、生成静态页面;getStaticPaths 声明需要预渲染的动态路由。

javascript
// pages/blog/[slug].js

// ① 声明要预渲染的路径(构建时确定)
export async function getStaticPaths() {
  const posts = await fetchAllPosts();
  return {
    paths: posts.map((p) => ({ params: { slug: p.slug } })),
    fallback: "blocking", // 未预渲染的路径首次访问时按需生成
  };
}

// ② 构建时为每个路径生成 props(打包成静态 HTML)
export async function getStaticProps({ params }) {
  const post = await fetchPost(params.slug);
  return {
    props: { post },
    revalidate: 60, // ★ 加上这行即变为 ISR:最多每 60s 后台再生一次
  };
}

export default function BlogPost({ post }) {
  return <article>{post.content}</article>;
}

ISR 的按需再验证(On-Demand Revalidation) ​

内容更新即时生效

除了基于时间的 revalidate,Next.js 还支持在内容变更时(如 CMS webhook 回调)主动触发指定页面重新生成,无需等待时间窗口,也无需整站重新构建。

javascript
// pages/api/revalidate.js —— CMS 更新后调用此接口
export default async function handler(req, res) {
  // 校验密钥,防止恶意刷新
  if (req.query.secret !== process.env.REVALIDATE_TOKEN) {
    return res.status(401).json({ message: "Invalid token" });
  }
  // 触发指定路径重新生成
  await res.revalidate(`/blog/${req.query.slug}`);
  return res.json({ revalidated: true });
}

SSR / SSG / ISR 三者对比 ​

维度SSR(getServerSideProps)SSG(getStaticProps)ISR(getStaticProps + revalidate)
渲染时机每次请求实时渲染构建时一次性预渲染构建时预渲染 + 后台按需再生
首屏性能好(需服务端计算)极好(CDN 直出)极好(CDN 直出)
内容新鲜度实时构建后固定,需重新构建准实时(revalidate 间隔内)
服务器成本高(每次都渲染)极低(无运行时渲染)低(仅到期时后台渲染)
适用场景高频变动的个性化页面文档、营销页等极少变动内容博客、商品详情等中低频更新内容

选型要点

不要把所有页面都做成 SSR。能静态化的尽量 SSG,需要一定新鲜度的用 ISR,只有真正强实时 / 强个性化(如用户后台、下单页)才用 SSR。这是 Next.js 性能优化的第一原则。


五、React Server Components(RSC) ​

核心概念

React Server Components(RSC,服务端组件) 是 React 18+ 引入的新范式:组件只在服务端运行,其代码不会打包进客户端 bundle,渲染结果以特殊的序列化格式流式传给浏览器。它与 SSR 不同——SSR 是"把组件渲染成 HTML 字符串",RSC 是"组件本身就活在服务端"。

RSC 与传统 SSR 的本质区别 ​

维度传统 SSR(含同构)React Server Components
组件运行位置服务端渲染一次 + 客户端注水服务端组件只在服务端跑
客户端 bundle组件代码要打包到客户端做注水服务端组件零客户端 JS
数据获取getServerSideProps 等外部钩子组件内直接 await fetch()
交互能力全部组件可交互需交互的部分标 'use client'

服务端组件 vs 客户端组件 ​

功能说明:默认所有组件都是服务端组件;需要状态、事件、浏览器 API 的组件用 'use client' 指令标记为客户端组件。

jsx
// app/page.jsx —— 默认即服务端组件(零客户端 bundle)
async function ProductList() {
  // 直接在组件内访问数据库 / API,无需 getServerSideProps
  const products = await db.product.findMany();
  return (
    <ul>
      {products.map((p) => (
        <ProductCard key={p.id} product={p} />
      ))}
    </ul>
  );
}

export default ProductList;
jsx
// app/LikeButton.jsx —— 客户端组件(有交互)
"use client";
import { useState } from "react";

export default function LikeButton() {
  const [liked, setLiked] = useState(false);
  return (
    <button onClick={() => setLiked(!liked)}>{liked ? "❤️" : "🤍"}</button>
  );
}

客户端边界(Client Boundary) ​

text
服务端组件 ProductList
   │ (零 JS 直接查库)
   ▼
ProductCard 服务端组件
   │ (导入并渲染)
   ▼
LikeButton 'use client'
   │ (打包进客户端 bundle)
   ▼
浏览器注水,支持交互

心智模型

把 'use client' 想象成一道边界线:线以上(服务端组件)负责数据获取与静态渲染、不进 bundle;线以下(客户端组件及其子树)负责交互、会进 bundle。合理下沉这道边界,能最大限度减小客户端 JS 体积。

RSC 使用限制

  • 服务端组件不能使用 useState、useEffect、事件处理器、浏览器 API

  • 客户端组件不能直接 import 服务端组件(但可通过 children 插槽传入)

  • RSC 目前深度绑定 Next.js App Router 等支持框架,尚不能脱离框架裸用


六、深度对比分析与选型指南 ​

技术指标量化对比 ​

评估维度传统 SSR现代 SSRCSR混合渲染
首屏时间100-300ms200-500ms500-2000ms300-800ms
可交互时间500-1000ms300-800ms1000-3000ms500-1200ms
SEO 支持度★★★★★★★★★★★★☆☆☆★★★★☆
开发复杂度★★☆☆☆★★★★☆★★★☆☆★★★★★
服务器成本★★☆☆☆★★★☆☆★★★★★★★★☆☆
用户体验★★☆☆☆★★★★☆★★★★★★★★★☆

场景化选型矩阵 ​

内容型网站(新闻、博客) ​

  • 推荐方案:现代 SSR(Next.js/Nuxt.js)
  • 理由:SEO 需求强烈,内容更新频繁,需要良好的首屏性能
  • 技术栈:Next.js + Headless CMS + CDN

企业级应用(管理后台、ERP) ​

  • 推荐方案:CSR + 优化
  • 理由:交互复杂,SEO 需求低,注重用户体验
  • 技术栈:React/Vue + 状态管理 + PWA

电商平台 ​

  • 推荐方案:混合渲染
  • 理由:商品页需要 SEO,个人中心需要丰富交互
  • 技术栈:Next.js(商品页) + SPA(用户中心)

移动端 Web 应用 ​

  • 推荐方案:CSR + PWA
  • 理由:原生应用体验,离线功能需求
  • 技术栈:Vue/React + Service Worker + 应用壳架构

混合渲染策略 ​

按路由差异化渲染 ​

功能说明:针对不同路由采用不同的渲染策略,平衡性能和 SEO 需求。

javascript
// Next.js 混合渲染配置
// next.config.js
module.exports = {
  async rewrites() {
    return [
      // 静态页面使用SSG
      { source: "/about", destination: "/about.html" },
      // 动态页面使用SSR
      { source: "/products/:id", destination: "/server/products/:id" },
      // API路由
      { source: "/api/:path*", destination: "/api/:path*" },
    ];
  },
};

边缘计算渲染 ​

功能说明:使用 Cloudflare Workers 实现边缘 SSR,减少延迟,提升全球用户体验。

javascript
// Cloudflare Workers实现边缘SSR
export default {
  async fetch(request, env) {
    const url = new URL(request.url);

    // 缓存检查
    const cacheKey = url.pathname;
    const cached = await env.CACHE.get(cacheKey);

    if (cached) {
      return new Response(cached, {
        headers: { "Content-Type": "text/html" },
      });
    }

    // 边缘渲染
    const html = await renderApp(url);

    // 设置缓存
    await env.CACHE.put(cacheKey, html, { expirationTtl: 3600 });

    return new Response(html, {
      headers: { "Content-Type": "text/html" },
    });
  },
};

七、Next.js 深度解析:Page Router vs App Router ​

两代路由方案

Page Router(pages/ 目录)是 Next.js 的经典方案,以"文件即页面"组织路由,数据获取靠 getServerSideProps / getStaticProps。 App Router(app/ 目录,Next.js 13+)是新一代方案,原生支持 React Server Components、嵌套布局、流式渲染,是官方主推方向。

架构哲学对比 ​

Page Router:文件即路由 ​

text
设计理念:基于页面的思维模型
pages/
  index.tsx          → /
  about.tsx          → /about
  blog/
    index.tsx        → /blog
    [slug].tsx       → /blog/xxx

App Router:组件化路由 ​

text
设计理念:基于组件的思维模型,支持布局共享和状态保持
app/
  layout.tsx         # 根布局
  page.tsx           → /
  about/
    page.tsx         → /about
  blog/
    layout.tsx       # 博客布局
    page.tsx         → /blog
    [slug]/
      page.tsx       → /blog/xxx

渲染模式技术细节 ​

Page Router 渲染生命周期 ​

功能说明:展示 Page Router 的页面级数据获取和渲染流程。

javascript
// 页面级数据获取
export async function getServerSideProps(context) {
  // 每次请求时执行
  const data = await fetchData(context.params);
  return { props: { data } };
}

export default function Page({ data }) {
  // 客户端注水
  return <div>{data}</div>;
}

App Router 组件级渲染 ​

功能说明:展示 App Router 的组件级渲染能力,包括服务端组件、客户端组件和布局组件的使用。

javascript
// 服务端组件 - 零客户端bundle
async function ServerComponent() {
  const data = await fetch("https://api.example.com/data");
  return <div>{data}</div>;
}

// 客户端组件 - 支持交互
("use client");
function ClientComponent() {
  const [state, setState] = useState();
  return <button onClick={() => setState()}>点击</button>;
}

// 布局组件 - 共享UI
export default function Layout({ children }) {
  return (
    <html>
      <body>
        <nav>导航栏</nav>
        {children}
      </body>
    </html>
  );
}

性能基准测试对比 ​

加载性能指标 ​

场景Page RouterApp Router提升幅度
首屏加载1.2s0.8s33%
可交互时间1.8s1.1s39%
Bundle 大小120KB85KB29%
LCP 指标2.1s1.4s33%

流式渲染性能优势 ​

javascript
// App Router流式渲染示例
export default async function Page() {
  return (
    <section>
      <Suspense fallback={<div>加载用户信息...</div>}>
        <UserProfile />
      </Suspense>

      <Suspense fallback={<div>加载商品列表...</div>}>
        <ProductList />
      </Suspense>
    </section>
  );
}

async function UserProfile() {
  // 快速返回的数据
  const user = await fetchUser();
  return <div>欢迎, {user.name}</div>;
}

async function ProductList() {
  // 慢速查询的数据
  const products = await fetchProducts();
  return products.map((product) => <div key={product.id}>{product.name}</div>);
}

迁移策略与最佳实践 ​

渐进式迁移方案 ​

javascript
// 步骤1:并行运行两个Router
// next.config.js
module.exports = {
  experimental: {
    appDir: true, // 启用App Router
  },
};

// 步骤2:逐步迁移页面
// app/legacy/[...slug]/page.tsx
export default function LegacyPage({ params }) {
  // 重定向到pages目录下的旧页面
  redirect(`/old/${params.slug.join("/")}`);
}

// 步骤3:新功能使用App Router

混合渲染配置 ​

javascript
// 针对不同路由采用不同策略
export const dynamicParams = true;

export async function generateStaticParams() {
  // 静态生成高频页面
  return [{ id: "1" }, { id: "2" }];
}

export async function generateMetadata({ params }) {
  // 动态生成元数据
  const product = await fetchProduct(params.id);
  return { title: product.name };
}

export default async function Page({ params }) {
  // 服务端渲染
  const product = await fetchProduct(params.id);
  return <ProductDetail product={product} />;
}

八、未来趋势与演进方向 ​

边缘渲染的兴起 ​

  • 边缘计算平台:Vercel Edge Functions, Cloudflare Workers
  • 优势:更低延迟,更好的全球化部署
  • 技术栈:React Server Components + 边缘运行时

AI 驱动的渲染优化 ​

javascript
// 智能预渲染示例
async function smartPrerender(userBehavior) {
  const prediction = await AIPredictor.predictNextPages(userBehavior);

  prediction.pages.forEach((page) => {
    // 预渲染预测页面
    prerenderPage(page.url);
  });
}

WebAssembly 在渲染中的应用 ​

  • 高性能计算:复杂的图形渲染、数据处理
  • 跨语言能力:Rust、C++编写的组件在浏览器中运行
  • 混合渲染:Wasm + JavaScript 协同工作

结语

渲染方案没有银弹,本质是在首屏性能、SEO、交互体验、服务器成本之间做权衡:静态内容用 SSG / ISR,动态个性化用 SSR,重交互轻 SEO 用 CSR,追求极致体积再引入 RSC。理解每种范式"在哪里渲染、渲染几次、代码跑在哪端",就能在项目中做出合理的架构取舍。