9-2 最佳实践合理的项目工程目录
随着项目规模增长,AppModule 中的导入列表会越来越长。本节通过模块分组和目录重构,将 AppModule 控制在 50 行以内,建立清晰的工程目录规范。
一、模块划分原则
1. 判断标准:AppModule 不超过 150 行
如果 app.module.ts 的代码行数超过 150 行,说明模块划分需要优化。优化后目标:不超过 50 行。
2. 功能性分组原则
将相关联的功能模块放在同一个 Module 中管理,导入一个 Module 即可引入整组功能。
3. 模块三大分类
| 分类 | 说明 | 位置 | 示例 |
|---|---|---|---|
| 公共模块 | 全局通用,直接在 AppModule 中导入 | src/ 根目录 | CacheModule, LoggerModule, ConfigModule, DatabaseModule, SharedModule |
| 功能模块 | 按业务功能聚合,通过 Module 嵌套导入 | src/access-control/, src/modules/ | AccessControlModule, FeatureModule |
| 条件模块 | 第三方可选依赖,按需加载 | src/conditional/ | ConditionalModule (邮件、短信等) |
二、目录结构重构
重构前
src/
├── app.module.ts ← 导入 15+ 模块,超过 150 行
├── role/
├── permission/
├── policy/
├── menu/
├── casl/
├── auth/
├── user/
├── prisma/
├── mail/
├── logger/
├── cache/
└── ...
text
重构后
src/
├── app.module.ts ← 不超过 50 行
│
├── access-control/ ← 权限控制功能模块
│ ├── access-control.module.ts ← 聚合所有权限相关模块
│ ├── role/
│ ├── permission/
│ ├── policy/
│ ├── menu/
│ ├── casl/
│ └── auth/
│
├── conditional/ ← 第三方可选模块
│ ├── conditional.module.ts
│ └── mail/
│
├── common/ ← 公共模块
│ ├── pipes/
│ ├── decorators/
│ ├── guards/
│ └── interceptors/
│
├── modules/ ← 业务特性模块
│ ├── feature.module.ts ← 聚合所有业务模块
│ ├── course/ ← 后续新增业务
│ ├── content/
│ └── attachment/
│
├── prisma/ ← 数据库模块
├── config/ ← 配置模块
├── logger/ ← 日志模块
├── cache/ ← 缓存模块
└── user/ ← 用户模块(被多处引用)
text
三、模块创建命令
# 创建权限控制聚合模块
nest g module access-control --no-spec --flat
# 创建条件模块
nest g module conditional --no-spec --flat
# 创建业务特性模块
nest g module modules/feature --no-spec --flat
bash
四、聚合模块的实现
1. AccessControlModule(权限控制)
// src/access-control/access-control.module.ts
import { Module } from '@nestjs/common';
import { RoleModule } from './role/role.module';
import { PermissionModule } from './permission/permission.module';
import { PolicyModule } from './policy/policy.module';
import { MenuModule } from './menu/menu.module';
import { CaslModule } from './casl/casl.module';
import { AuthModule } from './auth/auth.module';
@Module({
imports: [
RoleModule,
PermissionModule,
PolicyModule,
MenuModule,
CaslModule,
AuthModule,
],
})
export class AccessControlModule {}
typescript
2. ConditionalModule(条件加载)
// src/conditional/conditional.module.ts
import { Module } from '@nestjs/common';
import { MailModule } from './mail/mail.module';
@Module({
imports: [
// 根据 .env 配置条件导入第三方模块
...(process.env.MAIL_ENABLED === 'true' ? [MailModule] : []),
],
})
export class ConditionalModule {}
typescript
3. FeatureModule(业务特性)
// src/modules/feature.module.ts
import { Module } from '@nestjs/common';
// 后续新增业务模块在此导入
// import { CourseModule } from './course/course.module';
// import { ContentModule } from './content/content.module';
// import { AttachmentModule } from './attachment/attachment.module';
@Module({
imports: [
// 业务模块列表
],
})
export class FeatureModule {}
typescript
五、重构后的 AppModule
// src/app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { CacheModule } from './cache/cache.module';
import { LoggerModule } from './logger/logger.module';
import { PrismaModule } from './prisma/prisma.module';
import { SharedModule } from './shared/shared.module';
import { AccessControlModule } from './access-control/access-control.module';
import { ConditionalModule } from './conditional/conditional.module';
import { FeatureModule } from './modules/feature.module';
@Module({
imports: [
// 公共模块(全局)
ConfigModule.forRoot({ isGlobal: true }),
PrismaModule,
SharedModule,
LoggerModule,
CacheModule,
// 功能模块
AccessControlModule,
ConditionalModule,
// 业务模块
FeatureModule,
],
})
export class AppModule {}
typescript
代码行数:约 30 行,清晰明了。
六、目录管理规范
| 规范 | 说明 |
|---|---|
| 一个目录一个 module.ts | 每个目录下最多只有一个 *.module.ts 作为入口 |
| 子目录管理子模块 | 功能模块的子模块放在子目录中,NestJS CLI 会自动更新父模块 |
| 业务模块放 modules/ | 所有业务相关模块统一创建在 src/modules/ 下 |
| 新增业务流程 | nest g resource modules/<name> --no-spec |
七、后续新增业务的标准流程
# 1. 在 modules 目录下创建新业务模块
nest g resource modules/course --no-spec
nest g resource modules/content --no-spec
nest g resource modules/attachment --no-spec
# 2. 在 feature.module.ts 中导入新模块
# 3. 开始开发业务逻辑
bash
八、NestJS CLI 目录行为说明
当使用 nest g module 创建子目录中的模块时:
# 创建 src/modules/course/course.module.ts
# NestJS CLI 会自动更新 src/modules/feature.module.ts 的 imports
nest g module modules/course
bash
注意:NestJS CLI 会自动查找最近的上层
module.ts并更新其 imports。因此建议每个目录层级只有一个module.ts。
九、总结
| 要点 | 说明 |
|---|---|
| 150 行法则 | AppModule 超过 150 行需要重构分组 |
| 三大分类 | 公共模块、功能模块、条件模块 |
| 聚合模式 | 通过 Module 的 imports 嵌套管理子模块 |
| 目录规范 | 业务放 modules/,权限放 access-control/,第三方放 conditional/ |
| CLI 自动化 | NestJS CLI 自动更新父模块的 imports |
| 可扩展性 | 新增业务只需 nest g resource modules/<name> |
↑