企业级项目结构设计的思考与实践 —— 以 PawHaven 为例

PawHaven 是一个基于 React + Node.js 的开源全栈项目。通过它,你可以学习如何从 0 开始构建一个企业级应用:从前端到后端,从代码到 CI/CD,再到云部署,涵盖完整的最佳实践。

本文就是基于 PawHaven 的架构与实践经验整理而成,如果你想查看更多可运行的代码示例,可前往 GitHub仓库 深入了解,并且给一个 star ⭐️。


1. 项目背景与设计初衷

PawHaven 在设计之初,我就明确了几个关键目标:

  • 高扩展性:未来可能增加新的功能模块,如捐赠系统、志愿者管理、移动端应用等。
  • 高可维护性:支持长期运营和多人协作,降低后期维护成本。
  • 全球贡献者友好:项目开源后可能会有来自不同地区的贡献者,代码结构必须清晰、标准化,便于快速上手。

这些目标直接决定了 PawHaven 从一开始就不能沿用临时、零散的项目结构,而必须采用企业级的架构设计。


2. 常见项目结构及其局限性

2.1 传统"按功能类型拆分"结构

许多项目教程推荐如下结构:

js 复制代码
src
├─ components
├─ assets
├─ pages
├─ utils
├─ apis
├─ store

这种结构的优点是简单直观,适合小型项目或快速原型开发。但对于复杂大型应用,存在以下

局限性

  • 功能逻辑分散:一个业务模块的代码可能散落在 pagesstorecomponentsservices 中。
  • 修改成本高:每次修改或调试功能,需要在多个目录搜索相关文件。
  • 业务边界模糊:容易导致模块耦合,团队协作效率低,难以分工。
  • 难以扩展:新增功能时,可能需要在多个目录创建文件,增加复杂度。
  • 维护困难:对于大型历史项目,这种结构会显著增加维护成本和团队沟通难度。

2.2 DDD( Domain-Driven Design )模式

企业级复杂项目通常采用 业务驱动设计(DDD)

  • 一级目录是业务模块(feature)
  • 每个 feature 自包含所有相关逻辑:组件、页面、状态、服务、类型
  • shared 模块仅存放跨业务、可复用的通用能力

优点

  • 模块自包含:修改 feature 时无需跨目录查找
  • 业务边界清晰:团队成员可以独立开发或测试模块
  • 高扩展性:新业务模块可以平滑加入
  • 易于维护:降低了代码耦合度,提升了可读性

2.3 PawHaven 的 DDD 实践

在 PawHaven 中,前端采用 feature-first 的目录设计:

js 复制代码
user
├─ src
│  ├─ features
│  │  ├─ RescueDetail
│  │  │  ├─ index.tsx
│  │  │  ├─ types.ts
│  │  │  ├─ rescueDetailSlice.ts
│  │  │  ├─ components
│  │  │  │  ├─ RescueTimeline.tsx
│  │  │  │  ├─ AnimalBasicInfo.tsx
│  │  │  │  └─ RescueInteraction.tsx
│  │  │  └─ apis
│  │  │     ├─ queries.ts
│  │  │     └─ request.ts
│  │  ├─ ReportStray
│  │  │  ├─ index.tsx
│  │  │  ├─ types.ts
│  │  │  ├─ constants.ts
│  │  │  ├─ reportStraySlice.ts
│  │  │  ├─ components
│  │  │  │  └─ ReportForm.tsx
│  │  │  └─ apis
│  │  │     ├─ requests.ts
│  │  │     └─ queries.ts

feature目录下,每个业务模块(如 RescueDetailReportStray)都包含:

  • 组件(components)
  • 页面(index.tsx)
  • 状态管理(rescueDetailSlice.ts)
  • API 请求(apis)
  • 类型定义(types.ts)
  • 常量(constants.ts)

这种设计使得每个业务模块高度自包含,便于团队成员独立开发和维护。


3.组件化分层策略

在企业级项目中,随着功能越来越复杂,光有 DDD 的业务划分还不够,还需要进一步的 分层策略。在 PawHaven 中,我把「分层」不仅仅理解为 UI 组件的层次,而是所有代码单元(组件、hooks、服务、工具函数等)的合理归类和边界控制。

具体来说,PawHaven 的分层策略包括:

3.1 Feature 层(feature 内部)

  • 紧密绑定业务逻辑的内容。
  • 每个 feature 内部自包含页面、业务组件、hooks、服务、types 等。
  • 示例:report-animal/ReportForm.tsx、report-animal/hooks/useReportAnimal.ts。

3.2 跨 Feature 层(应用级)

  • 在不同业务模块之间共享,但仍然带有一定业务语境的内容。
  • 例如用户信息卡片、导航菜单、布局组件,或与多个业务相关的 hooks。
  • 通常放在应用层级目录下,而不是某个 feature 内部。

3.3 Shared 层(与业务无关的通用层)

  • 完全与业务逻辑无关的内容,包括 UI Dumb 组件(Button、Modal、Input)、工具函数、通用 hooks、常量、主题配置、国际化文案等。
  • 这些内容可以在整个 monorepo 内复用,未来也能很容易抽离为独立的库。

通过这种 组件化分层策略,PawHaven 的代码结构既保证了业务边界清晰,又确保了通用能力的复用性,从而达到了高扩展性与高可维护性的目标。


4. 单体结构 vs Monorepo

在企业级项目中,如何管理多个应用和模块是一项关键决策。常见的有两种方式:单体结构(Multi-Repo) 和 Monorepo。

4.1 单体结构(Multi-Repo)

单体结构是最常见的方式:每个服务或者业务一个仓库,工具库单独一个仓库。

优点:

  • 仓库独立,权限控制清晰
  • 各团队可独立开发与发布
  • 初期上手成本低

缺点:

  • 跨项目共享代码困难,经常出现重复造轮子
  • 依赖管理分散,容易出现版本冲突
  • 跨仓库重构复杂,维护成本高

实际案例: 像 Netflix、Spotify 的微服务体系,出于服务解耦的考虑,一直使用多仓库来管理各个服务。 我自己曾经深受单体结构的困扰,在多个项目间共享代码时,常常需要手动同步版本,导致依赖混乱和调试困难,同时本地开发期间,往往需要频繁切换不同仓库,极大降低了开发效率。 同时,开发人员经常由于麻烦而不愿意去更新共享库,导致各个项目间的代码质量和规范参差不齐,增加了维护难度。

4.2 Monorepo

Monorepo 是将多个应用、服务、库放在同一个代码仓库里统一管理。例如 Google 的 Monorepo 就包含了数十万开发者使用的代码。

优点:

  • 代码共享方便:多个服务都能直接依赖 shared 模块
  • 统一依赖和规范:ESLint、Prettier、CI/CD 流程可以一次配置全局生效
  • 跨项目重构简单:改动一个 shared 模块,所有依赖应用立即受益
  • 开发体验好:开发者在一个仓库内即可完成全部工作

缺点:

  • 对工具链要求更高,需要额外的构建与工作区管理能力
  • 随着代码库增大,构建和测试需要优化策略

实际案例:

  • Google:全球最大的 Monorepo,支撑了 Gmail、Search、Ads 等所有核心产品
  • Meta(Facebook):前端、移动端、后端共享同一 Monorepo
  • Uber、Airbnb:逐步迁移到 Monorepo,以提升团队协作和重构能力

我当前公司所在项目经历了由单体结构到 Monorepo的整改,开发人员普遍感受到开发效率的提升以及可复用代码的增加

4.3 PawHaven 为什么选择 Monorepo

考虑到 PawHaven 的发展方向:

  • 会同时有 前端用户端(pawHaven)、前端管理端(admin)、鉴权应用(auth) 等多个应用
  • 同时还会有 多个后端微服务服务(NestJS) 和 shared 包
  • 将来可能会有全球贡献者参与,需要快速理解代码结构并统一规范

因此,Monorepo 是最合适的选择。

在 PawHaven 中,目录结构如下:

js 复制代码
PawHaven-frontend/
├── apps/                  # 具体应用
│   ├── user/          # 用户端
│   ├── admin/             # 后台管理端
├── packages/       # 通用模块
│   ├── components/
│   ├── hooks/
│   ├── utils/
│   ├── constants/
│   ├── theme/
│   ├── i18n/
│   └── api-client/
├── package.json
└── pnpm-workspace.yaml

4.4. 为什么选择 pnpm 实现 Monorepo

市面上有多种 Monorepo 工具(如 Lerna、Nx、Turborepo),我最终选择了 pnpm workspace,原因是:

  • 高效安装:基于硬链接和内容寻址,节省磁盘空间和安装时间,相比 npm/yarn 本地开发体验更好
  • 严格依赖隔离:避免"幽灵依赖"问题,保证依赖声明清晰
  • 原生支持 workspace:轻量、配置简单,直接支持 Monorepo 管理
  • 与企业实践契合:pnpm 已在很多大厂和社区项目中被广泛使用

pawHaven配置:

yaml 复制代码
// pnpm-workspace.yaml
packages:
 - 'apps/*'
 - 'packages/*'
 

apps 目录下存放各个前端应用,packages 目录下存放共享模块。通过 workspace,可以轻松实现跨应用依赖和版本管理。

这样多个前端或者后端服务可以在同一仓库内协作开发,同时保持各自的独立构建与部署能力。


5. 总结

通过 PawHaven 的实践,我们可以看到,企业级项目的架构设计不仅仅是代码组织问题,更关乎可扩展性、可维护性和团队协作效率。

PawHaven 从一开始就采用 DDD / Feature-first 的模式,将每个业务模块自包含,保证业务边界清晰;通过 组件化分层策略,合理划分 Feature 层、跨 Feature 层和 Shared 层,提升模块复用性和可维护性;而 Monorepo + pnpm workspace 的方案,使前后端及共享模块统一管理,同时保持职责分离,让开发者可以快速上手并高效协作。

这样的架构设计不仅为当前开发提供便利,也为未来功能扩展、团队协作和全球贡献者的加入打下坚实基础。

相关推荐
若无_2 小时前
深入理解 Vue 中的 reactive 与 ref:响应式数据的两种核心实现
前端·vue.js
玄魂2 小时前
一键生成国庆节祝福海报,给你的朋友圈上点颜色
前端·javascript·数据可视化
彼日花2 小时前
前端新人30天:从手足无措到融入团队
前端·程序员
搞科研的小刘选手3 小时前
【学术会议合集】2025-2026年地球科学/遥感方向会议征稿信息
大数据·前端·人工智能·自动化·制造·地球科学·遥感测绘
蓝莓味的口香糖3 小时前
【CSS】flex布局
前端·css
柳贯一(逆流河版)3 小时前
Gateway 集成 JWT 身份认证:微服务统一认证的实战指南
微服务·架构·gateway
彩旗工作室4 小时前
用 Supabase 打造统一认证中心:为多应用提供单点登录(SSO)
服务器·前端·数据库
EveryPossible4 小时前
第一版代码
前端·javascript·css
ObjectX前端实验室4 小时前
【图形编辑器架构】渲染层篇 — 从 React 到 Canvas 的声明式渲染实现
前端·计算机图形学·图形学