全栈框架模块化怎么拆分?

访客 全栈框架 2

本文目录导读:

  1. 核心原则:关注点分离 + 高内聚低耦合
  2. 水平分域:按“业务模块”拆分(最推荐)
  3. 垂直分层:按“技术层次”拆分(通用层)
  4. 关键拆分策略(实操技巧)
  5. 实战案例:一个“电商后台”的拆分
  6. 总结:你应该按哪个拆?

这是一个非常核心且复杂的问题,全栈框架的模块化拆分没有“银弹”,它依赖于项目规模、团队结构、技术栈(如Next.js, Nuxt, Remix, Django/React等)以及业务领域

模块化拆分可以从两个维度进行:垂直分层(技术视角)水平分域(业务视角)

以下是一套适用于现代全栈(特别是前后端融合框架如Next.js、Nuxt、SvelteKit或T3 Stack)的通用拆分方法论。


核心原则:关注点分离 + 高内聚低耦合

你的代码应该像乐高积木,而非意大利面条。

水平分域:按“业务模块”拆分(最推荐)

这是最符合产品逻辑的拆分方式,想象你的应用有“用户中心”、“商品管理”、“订单系统”三大块。

目录结构示例(以Next.js App Router为例):

my-app/
├── src/
│   ├── modules/           # 核心业务模块(水平拆分)
│   │   ├── auth/          # 1. 认证模块
│   │   │   ├── components/   # 仅属于auth的UI组件
│   │   │   ├── api/          # 仅属于auth的API路由 (Next.js Route Handlers)
│   │   │   ├── hooks/        # 仅属于auth的React hooks
│   │   │   ├── lib/          # 仅属于auth的纯函数、验证逻辑
│   │   │   └── types/        # 仅属于auth的TypeScript类型
│   │   │
│   │   ├── products/      # 2. 商品模块
│   │   │   ├── components/
│   │   │   ├── api/
│   │   │   ├── hooks/
│   │   │   └── types/
│   │   │
│   │   └── orders/        # 3. 订单模块
│   │       ├── components/
│   │       ├── api/
│   │       └── types/
│   │
│   ├── shared/            # 全局共享层(垂直分层)
│   │   ├── ui/            # 通用UI组件 (Button, Card, Modal)
│   │   ├── lib/           # 通用工具函数 (date, format, API client)
│   │   ├── config/        # 环境变量、常量
│   │   └── middleware/    # 全局中间件 (如权限校验)
│   │
│   └── app/               # Next.js App Router 入口 (页面路由)
│       ├── layout.tsx
│       ├── page.tsx
│       ├── auth/          # 页面路由指向 auth 模块
│       └── products/      # 页面路由指向 products 模块

这样做的好处:

  • 高内聚:修改“订单”逻辑,只需改动 modules/orders 文件夹,不影响“商品”。
  • 可裁剪:如果后期要拆成微前端,可以直接将 modules/orders 整个打包成独立应用。
  • 职责清晰:新人入职只需阅读相关 modules 即可理解业务。

垂直分层:按“技术层次”拆分(通用层)

任何模块内部,都应遵循清晰的技术分层。

层级 职责 严禁做的事
Presenter (UI) 页面组件、布局、交互逻辑 直接读写数据库、调用后端API原始数据
Hooks / State 管理组件状态、副作用处理(React Query, Zustand) 包含复杂业务逻辑(应调用下方服务)
Services / API 发起网络请求、调用外部API、处理数据格式化 直接操作DOM或React状态
Database (ORM) Prisma Schema, Drizzle, Mongoose Models 暴露给UI层直接的数据库操作
Types / Schema Zod / Zodios / TypeScript类型定义,定义契约 在UI层硬编码类型(保持共享)

在模块内部的应用:

// modules/orders/api/create-order.ts (API层)
export async function createOrder(data: CreateOrderInput) {
  // 1. 验证
  // 2. 调用Prisma/SQL
  // 3. 调用支付网关
  // 4. 返回结果
}
// modules/orders/hooks/use-create-order.ts (Hooks层)
export function useCreateOrder() {
  const mutation = useMutation({ mutationFn: createOrder });
  // ... react-query 逻辑
  return { ...mutation };
}
// modules/orders/components/order-form.tsx (UI层)
function OrderForm() {
  const { mutate } = useCreateOrder();
  // 只负责渲染表单并调用 mutate
}

关键拆分策略(实操技巧)

共享内核(Shared Kernel)

所有模块都可能用的极难变更的东西收拢到 sharedlib 文件夹。

  • 禁止:把业务相关的API、Schema放在shared里。createUser 函数不应该在shared里,它应该属于 modules/auth

数据流(Data Flow)契约化

使用 Zod / TypeScript 定义模块间的数据接口。

// modules/auth/types/user.ts
export interface User {
  id: string;
  name: string;
  email: string;
}
// modules/orders/types/order.ts
import type { User } from '@/modules/auth/types';
export interface Order {
  id: string;
  user: User; // 引用其他模块的类型,但保持明确的导入关系
  total: number;
}

后端与前端边界(BFF - Backend For Frontend)

全栈框架(Next.js API Routes, Nuxt Server)天然充当了BFF层。

  • 不要:在前端组件里直接 fetch('https://external.com/api')
  • :通过框架自身API路由做代理或聚合,实现后端防护(隐藏秘钥、数据裁剪)。

实战案例:一个“电商后台”的拆分

假设使用 Next.js + Prisma + tRPC(类型安全RPC框架)。

src/
├── modules/
│   ├── auth/          # 登录、注册、权限
│   │   ├── components/ (LoginForm.tsx)
│   │   ├── server/    (auth.router.ts - tRPC路由)
│   │   └── schemas/   (zod schemas for validation)
│   │
│   ├── inventory/     # 库存管理(独立模块)
│   │   ├── components/
│   │   ├── server/    (inventory.router.ts)
│   │   └── schemas/   (inventory-schema.ts)
│   │
│   └── analytics/     # 数据分析(后期大模块,甚至可独立部署)
│       └── ...
│
├── shared/
│   ├── ui/            # shadcn/ui 组件
│   ├── lib/           # db.ts (Prisma Client初始化), api-client.ts
│   └── types/         # 全局枚举、常量
│
├── app/               # 页面路由(根据业务模块组织文件夹)
│   ├── (auth)/        # 路由组,用于登录/注册页面布局
│   ├── (dashboard)/
│   │   ├── inventory/
│   │   └── orders/
│   └── api/           # tRPC API路由 或 Next.js Route Handlers
│       └── trpc/
│           └── [trpc].ts

你应该按哪个拆?

  1. 小项目/原型(<5个页面):先按垂直分层/components, /hooks, /api),模块化会带来额外心智负担。
  2. 中等项目(5-20个页面,2-5人团队):强烈建议使用 src/modules/(水平),这是最平衡的选择,业务逻辑清晰,团队协作高效。
  3. 大型项目(微前端/多团队):考虑Monorepo (Turborepo / Nx) + 独立包(Packages)。
    packages/
      ├── ui/          # 共享UI组件库
      ├── config/      # 共享eslint, tsconfig
      ├── auth/        # 独立发布包(模块独立)
      └── order/       # 独立发布包
    apps/
      ├── admin/       # 后台(引入 auth, order包)
      └── store/       # 前台(引入 auth 包)

一句话建议: 先以 modules/ 按业务拆分,再在每个模块内部做垂直分层,比单层的 components/utils/ 要好维护得多。

标签: 微服务 模块解耦

抱歉,评论功能暂时关闭!