“我们不只是开发功能,更在搭建一座长期可演化的工程大厦。”
在 React Server Components(RSC) 和 Next.js App Router 成为主流架构范式的今天,许多开发者仍在“性能”和“结构混乱”之间痛苦拉扯。本文将分享我在真实项目中不断试验、打磨,最终沉淀下来的架构设计方法——RSC 优先的五层架构模型(5-Layer Architecture) 。
它不仅提升了性能,更彻底解决了可维护性和可控性问题。
❌ 默认目录结构的问题
很多基于 Next.js 构建的项目会逐步陷入以下困境:
- Client 组件边界不清,污染了原本能 SSR 的组件
- 过度依赖
index.ts导致依赖边界不清晰 - 首屏加载变慢,LCP 高、TBT 爆炸、JS 包臃肿
- 小改动带来系统性结构崩溃,维护代价极高
经过多轮战斗之后,我终于明白:
架构应该服务于团队的长期演进,而不是阻碍它。
于是我彻底推翻原有结构,从零构建了一套新模型。
🧱 五层架构模型简介
RootLayout → Page Layout → Page → View → Component
每一层都有职责边界,并有明确建议,尽可能保持 React Tree 的“RSC 主导性”,将 Client 组件(CSC)限制在叶子节点。
| 层级 | 职责说明 | 是否允许 CSC | 是否允许改动 |
|---|---|---|---|
| RootLayout | 顶层布局:定义 <html>、全局 Provider、样式等 | ❌ 禁止 | ❌ 冻结不可改 |
| Page Layout | 路由级布局:如主框架导航栏、布局结构 | ❌ 禁止 | ❌ 冻结不可改 |
| Page | 页面入口:生成 Metadata,调用唯一 View | ❌ 禁止 | ❌ 冻结不可改 |
| View | 视图层:组合多个组件构成完整页面 | ✅ 可使用 CSC(建议 RSC 主导) | ✅ 可随时调整 |
| Component | 原子组件:具备 UI 行为逻辑,可含 useState/useEffect | ✅ 允许 | ✅ 可随时修改 |
✅ 架构执行规则
1️⃣ RSC 可以直接 import CSC,无需 dynamic 包装
官方推荐写法:Server Component 可以直接 import Client Component,Next.js 编译器会自动在 React Flight 中生成客户端边界,不会污染上层。
// ✅ 合法:RSC 直接使用 CSC(如导航栏、表单等)
import { NavBar } from '@/components/navbar.csc';
✅ 是否使用
dynamic()包装,由场景决定:重型组件、非首屏交互才建议懒加载。
2️⃣ CSC 不得静态 import RSC(必须通过 props/children 传递)
Client Component 无法渲染或执行真正的 Server Component,否则会导致降级或直接编译错误。
// ✅ 合法:通过 props 接收父级 RSC 提供的节点
export function ClientWrapper({children}: { children: ReactNode }) {
return <div>{ children }</div>;
}
// ❌ 非法:CSC 中静态 import RSC 文件
import { ServerBlock } from '@/components/xxx.rsc';
3️⃣ 重型 CSC 建议使用 dynamic 懒加载(可选)
对于富文本、图表、地图等大体积 CSC,可通过 next/dynamic 延迟加载:
const Chart = dynamic(() => import('./chart.csc'), {ssr: false});
4️⃣ Page 只返回一个 View,View 自由组织结构
export default async function Page() {
return <ImageResizeView/>;
}
View 允许组合多个 RSC 与 CSC,但建议将所有副作用集中在叶子节点组件中处理,保持 View 本身纯粹。
📁 目录结构示例(推荐)
/src
├── app
│ ├── layout.tsx # RootLayout
│ └── [locale]
│ ├── layout.tsx # Page Layout
│ └── tools
│ └── image-compress
│ └── page.tsx # Page
├── features
│ └── image-compress
│ └── image-compress.view.tsx # View
└── components
├── ui/
└── widgets/
├── compress-chart.csc.tsx # Client Component
└── compress-chart.lazy.tsx # 懒加载入口(可选)
🚀 实际收益提升
这套架构在我主导的 Toolbox 项目中已经应用于数十个工具页面,收获如下:
| Page | 原始:FLJ(KB) | 评分 | 一阶段优化:FLJ(KB) | 评分 | 二阶段优化:FLJ(KB) | 三阶段优化:FLJ(KB) | 评分 |
|---|---|---|---|---|---|---|---|
| home | 479 | 42 | 289 | 83 | 291 | 162 | |
| about-us | 409 | 53 | 189 | 95 | 189 | 157 | |
| privacy-policy | 407 | 50 | 169 | 99 | 170 | 170 | |
| terms-of-service | 407 | 48 | 169 | 97 | 170 | 170 | |
| checkout/result | 981 | 42 | 315 | 88 | 254 | 223 | |
| tools | 480 | 58 | 252 | 95 | 251 | 177 | |
| image-compress | 1158 | 35 | 271 | 93 | 246 | 185 | 98 |
| image-convert | 1147 | 38 | 271 | 95 | 246 | 185 | 95 |
| image-crop | 1219 | 40 | 270 | 94 | 246 | 185 | 95 |
| image-resize | 1158 | 39 | 271 | 96 | 246 | 185 | 97 |
| qr-code | 1300 | 42 | 264 | 95 | 236 | 176 | 99 |
| calc-bmi | 870 | 38 | 265 | 97 | 237 | 176 | 98 |
| text-format | 762 | 45 | 264 | 81 | 236 | 176 | 97 |
| world-clock | 584 | 51 | 264 | 92 | 236 | 176 | 96 |
| base-convert | 864 | 55 | 264 | 93 | 236 | 176 | 96 |
| 指标 | 优化前 → 优化后 |
|---|---|
| Lighthouse 分数 | 提升 15–30 分 |
| TBT | 降至 100ms 以下 |
| 首屏 JS(FLJ) | 缩减 300KB+ |
| LCP | 控制在 2.5s 内 |
| 团队协作 | 职责边界清晰,写代码不迷路 |
next build 全部页面 FLJ大幅降低,页面需要处理的JS少了,自然也就快了!
🧠 写在最后
这套五层架构模型,适用于一切追求:
- ✅ 高性能
- ✅ 可维护性
- ✅ RSC-first
- ✅ SEO优化
的中大型 Next.js 项目。 它并不是一套通用的“套路”,而是一种严肃、稳定、可验证的架构哲学。
你需要做的,就是让复杂留在边界,把副作用约束在叶子。
👨💻 作者:AiMuo / Toolbox 项目 📎 项目地址:aimuo.com 📌 更多工程实践持续分享中,欢迎关注!