我用五层架构重建了整个 Next.js 项目,从污染地狱爬上了性能天堂

994 阅读4分钟

“我们不只是开发功能,更在搭建一座长期可演化的工程大厦。”

在 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)评分
home4794228983291162
about-us4095318995189157
privacy-policy4075016999170170
terms-of-service4074816997170170
checkout/result9814231588254223
tools4805825295251177
image-compress1158352719324618598
image-convert1147382719524618595
image-crop1219402709424618595
image-resize1158392719624618597
qr-code1300422649523617699
calc-bmi870382659723717698
text-format762452648123617697
world-clock584512649223617696
base-convert864552649323617696
指标优化前 → 优化后
Lighthouse 分数提升 15–30 分
TBT降至 100ms 以下
首屏 JS(FLJ)缩减 300KB+
LCP控制在 2.5s 内
团队协作职责边界清晰,写代码不迷路

next build 全部页面 FLJ大幅降低,页面需要处理的JS少了,自然也就快了!

perf_build_result.png

lighthouse_99.png


🧠 写在最后

这套五层架构模型,适用于一切追求:

  • ✅ 高性能
  • ✅ 可维护性
  • ✅ RSC-first
  • ✅ SEO优化

的中大型 Next.js 项目。 它并不是一套通用的“套路”,而是一种严肃、稳定、可验证的架构哲学

你需要做的,就是让复杂留在边界,把副作用约束在叶子。


👨‍💻 作者:AiMuo / Toolbox 项目 📎 项目地址:aimuo.com 📌 更多工程实践持续分享中,欢迎关注!