为什么选择 App Router?

Next.js 13 引入了全新的 App Router,到了 14 版本已经非常稳定。相比传统的 Pages Router,App Router 带来了:

  • React Server Components (RSC) — 默认在服务端渲染,零客户端 JS
  • 嵌套布局 — 共享 UI 变得极其简单
  • 流式渲染 — 渐进式页面加载
  • 更强的类型安全 — 参数、搜索参数都有完整类型推断

项目结构

一个典型的 App Router 项目结构如下:

app/
├── layout.tsx          # 根布局
├── page.tsx            # 首页
├── posts/
│   ├── layout.tsx      # 文章页共享布局
│   └── [slug]/
│       └── page.tsx    # 文章详情
└── api/
    └── posts/
        └── route.ts    # API 路由

核心概念

1. Server Components(默认)

在 App Router 中,所有组件默认都是 服务端组件。这意味着:

// 这是一个服务端组件 — 可以直接访问文件系统、数据库
import fs from "fs";

export default async function PostList() {
  const posts = await getPosts(); // 直接 await,不需要 useEffect
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.slug}>{post.title}</li>
      ))}
    </ul>
  );
}

2. Client Components

当需要交互时,加上 "use client" 指令:

"use client";

import { useState } from "react";

export function ThemeToggle() {
  const [dark, setDark] = useState(false);
  return <button onClick={() => setDark(!dark)}>切换主题</button>;
}

3. 静态生成

对于博客类的站点,静态导出是最佳选择:

// next.config.ts
const config: NextConfig = {
  output: "export",
};

配合 generateStaticParams

export function generateStaticParams() {
  const posts = getAllPosts();
  return posts.map((post) => ({ slug: post.slug }));
}

数据获取模式

场景方法适用
静态内容generateStaticParams + 直接读取博客、文档
动态内容Server Component + fetch实时数据
客户端数据useEffect + fetch用户特定数据

性能优化建议

  1. 减少 Client Components — 尽可能让组件保持在服务端
  2. 使用 next/image — 自动优化图片
  3. 字体优化 — 使用 next/font 避免布局偏移
  4. 流式渲染 — 用 loading.tsxSuspense 提升感知性能

总结

App Router 代表了 React 全栈框架的未来方向。它让你能在一个项目里灵活混合服务端和客户端渲染,写出更简洁、更高性能的应用。

对于个人博客这种内容型站点,静态导出 + Markdown 的组合几乎是最优解 — 这也是本站采用的技术方案。