覆盖文档:Introduction, First Steps, CLI Overview, CLI Scripts, CLI Workspaces 前置知识:Node.js 基础, TypeScript 基础 源码重点:
packages/core/nest-factory.ts,packages/core/constants.ts
一、NestJS 是什么
1.1 一句话定义
NestJS 是一个基于 Node.js 的渐进式服务端框架,用 TypeScript 构建,融合了面向对象编程(OOP)、函数式编程(FP)和函数响应式编程(FRP)的思想。
1.2 NestJS 与 Express/Fastify 的关系
┌────────────────────────────────────────┐
│ NestJS(架构层) │
│ 模块系统 + DI 容器 + 装饰器 + 管线 │
│ │
│ ┌─────────────┐ ┌─────────────────┐ │
│ │ Express │ │ Fastify │ │
│ │ (HTTP 引擎) │ │ (HTTP 引擎) │ │
│ └─────────────┘ └─────────────────┘ │
│ ↑ 默认 ↑ 可选 │
│ └───────────────────┘ │
│ AbstractHttpAdapter │
└────────────────────────────────────────┘
- Express 是一个极简的 HTTP 框架,处理请求/响应
- Fastify 是一个高性能 HTTP 框架,约 2 倍于 Express 的吞吐
- NestJS 不是 Express 的替代品,而是在 Express/Fastify 之上提供了企业级架构能力
NestJS 通过 AbstractHttpAdapter 抽象了底层 HTTP 引擎,核心代码不依赖任何具体 HTTP 库。
1.3 设计哲学
NestJS 的架构深受 Angular 启发:
| 概念 | Angular(前端) | NestJS(后端) |
|---|---|---|
| 模块 | @NgModule() | @Module() |
| 组件/控制器 | @Component() | @Controller() |
| 服务 | @Injectable() | @Injectable() |
| 依赖注入 | 构造器注入 | 构造器注入 |
| 装饰器 | 大量使用 | 大量使用 |
核心理念:约定优于配置,通过装饰器和模块系统提供可预测的代码组织方式。
二、环境准备与项目创建
2.1 环境要求
# 确认 Node.js 版本 >= 20
node --version
# 全局安装 Nest CLI
npm i -g @nestjs/cli
# 验证 CLI 安装
nest --version
2.2 创建项目
# 标准创建
nest new my-app
# 严格 TypeScript 模式(推荐)
nest new my-app --strict
# 选择包管理器:npm / yarn / pnpm
2.3 项目目录结构
my-app/
├── src/
│ ├── main.ts # 应用入口:创建并启动 NestJS 应用
│ ├── app.module.ts # 根模块:整个应用的组织入口
│ ├── app.controller.ts # 示例控制器:处理 HTTP 请求
│ ├── app.controller.spec.ts # 控制器的单元测试
│ └── app.service.ts # 示例服务:封装业务逻辑
├── test/
│ ├── app.e2e-spec.ts # 端到端测试
│ └── jest-e2e.json # E2E 测试配置
├── nest-cli.json # Nest CLI 配置
├── tsconfig.json # TypeScript 编译配置
├── tsconfig.build.json # 构建用 TS 配置
├── package.json # 项目依赖和脚本
└── eslint.config.mjs # ESLint 配置
2.4 核心文件解析
main.ts — 应用入口
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
// 1. 创建 NestJS 应用实例
const app = await NestFactory.create(AppModule);
// 2. 监听端口
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();
NestFactory.create() 是整个框架的入口,它完成了以下工作:
- 创建 DI 容器(
NestContainer) - 扫描模块树(
DependenciesScanner) - 实例化所有依赖(
InstanceLoader) - 注册路由(
RoutesResolver)
app.module.ts — 根模块
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [], // 导入其他模块
controllers: [AppController], // 注册控制器
providers: [AppService], // 注册服务(Provider)
})
export class AppModule {}
@Module() 装饰器定义了模块的四大属性:
imports:导入的依赖模块controllers:该模块包含的控制器providers:该模块包含的服务/提供者exports:导出给其他模块使用的提供者
app.controller.ts — 控制器
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}
@Controller()声明这是一个路由控制器@Get()将getHello()方法映射到GET /路由constructor(private readonly appService: AppService)— 通过构造器注入AppService
app.service.ts — 服务
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}
@Injectable()声明这个类可以被 NestJS 的 DI 容器管理和注入
2.5 启动与验证
# 开发模式(文件变更自动重启)
npm run start:dev
# 生产模式
npm run build
npm run start:prod
# 使用 SWC 加速编译(20x 提速)
npm run start -- -b swc
访问 http://localhost:3000,看到 Hello World! 即成功。
三、Nest CLI 工具链
3.1 核心命令
| 命令 | 别名 | 功能 |
|---|---|---|
nest new <name> | nest n | 创建新项目 |
nest generate <type> <name> | nest g | 代码生成 |
nest build | 编译项目 | |
nest start | 启动项目 | |
nest info | nest i | 显示系统信息 |
nest add <library> | 添加外部库 |
3.2 代码生成器(18 种 Schematic)
# 常用生成命令
nest g module users # 生成模块
nest g controller users # 生成控制器
nest g service users # 生成服务
nest g resource cats # 一键生成完整 CRUD(模块+控制器+服务+DTO+实体)
# 其他可生成的类型
nest g class # 普通类
nest g decorator # 装饰器
nest g filter # 异常过滤器
nest g gateway # WebSocket 网关
nest g guard # 守卫
nest g interceptor # 拦截器
nest g interface # 接口
nest g middleware # 中间件
nest g pipe # 管道
nest g provider # 提供者
nest g resolver # GraphQL 解析器
nest g library # 共享库(Monorepo)
nest g app # 子应用(Monorepo)
常用选项:
--dry-run:预览生成结果,不实际创建文件--no-spec:不生成测试文件--flat:不创建子目录
3.3 nest-cli.json 配置
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"builder": "tsc", // 编译器:tsc | swc | webpack
"typeCheck": true, // SWC 模式下是否做类型检查
"deleteOutDir": true, // 编译前清空输出目录
"assets": [], // 需要复制的非 TS 文件
"watchAssets": false // watch 模式下是否监控 assets
},
"generateOptions": {
"spec": true, // 是否生成测试文件
"flat": false // 是否使用扁平目录结构
}
}
3.4 脚本管理
推荐在 package.json 中使用本地安装的 CLI:
{
"scripts": {
"build": "nest build",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\"",
"test": "jest",
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"devDependencies": {
"@nestjs/cli": "^11.0.0"
}
}
本地安装 CLI 的优势:团队成员使用统一版本,避免全局版本冲突。
四、平台选择与多平台抽象
4.1 Express 平台(默认)
// 无需额外配置,默认使用 Express
const app = await NestFactory.create(AppModule);
特点:
- 生态最丰富,社区资源多
- 大量 Express 中间件可直接使用
- 适合绝大多数场景
4.2 Fastify 平台
npm i --save @nestjs/platform-fastify
import { NestFactory } from '@nestjs/core';
import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter(),
);
// Fastify 默认只监听 localhost,需显式指定 0.0.0.0
await app.listen(3000, '0.0.0.0');
}
bootstrap();
特点:
- 约 2 倍于 Express 的吞吐量
- 内置 JSON Schema 验证
- 不兼容所有 Express 中间件
4.3 平台差异对照
| 特性 | Express | Fastify |
|---|---|---|
| 性能 | 中等 | 高(~2x) |
| 中间件生态 | 极丰富 | 较少,但有对应插件 |
| 文件上传 | Multer(内置支持) | 需要额外处理 |
| 装饰器 | @Res() → Express Response | @Res() → Fastify Reply |
| JSON 解析 | body-parser | 内置 |
| 重定向 | res.redirect() | res.status(302).redirect() |
4.4 NestFactory 的三种创建方式
// 1. 创建完整 HTTP 应用(最常用)
const app = await NestFactory.create(AppModule);
// 2. 创建微服务
const app = await NestFactory.createMicroservice(AppModule, {
transport: Transport.TCP,
});
// 3. 创建应用上下文(无 HTTP,用于 CLI/CRON/Worker)
const ctx = await NestFactory.createApplicationContext(AppModule);
4.5 创建选项
const app = await NestFactory.create(AppModule, {
// 出错时退出进程(默认 true)
abortOnError: true,
// 日志配置:false 禁用 | 日志级别数组
logger: ['error', 'warn', 'log'],
// 是否启用 CORS
cors: true,
// 在 useLogger() 前缓冲日志
bufferLogs: false,
// 获取原始请求体(用于 Webhook 签名验证)
rawBody: false,
// 强制关闭连接(优雅关闭时不等待 Keep-Alive)
forceCloseConnections: false,
});
五、Monorepo 与工作区
5.1 Standard 模式 vs Monorepo 模式
| 特性 | Standard | Monorepo |
|---|---|---|
| 项目数 | 单个 | 多个应用 + 多个库 |
| 编译器 | tsc(默认) | webpack(默认) |
| 目录结构 | src/ | apps/ + libs/ |
| 共享代码 | 无 | libs/ 中的共享库 |
5.2 创建 Monorepo
# 在现有标准项目中添加子应用(自动转为 Monorepo)
nest g app admin-api
# 创建共享库
nest g library shared
# 构建指定项目
nest build admin-api
# 启动指定项目
nest start admin-api
转换后的目录结构:
my-workspace/
├── apps/
│ ├── my-app/ # 主应用
│ │ └── src/
│ └── admin-api/ # 子应用
│ └── src/
├── libs/
│ └── shared/ # 共享库
│ └── src/
├── nest-cli.json # 统一配置
└── tsconfig.json
5.3 共享库的使用
共享库通过 TypeScript path aliases 引用:
// 在任何应用中直接导入共享库
import { SharedModule } from '@app/shared';
共享库不能独立运行,必须被应用导入使用。
六、源码解读:NestFactory.create() 启动流程
[资深] 本节面向希望深入理解框架内部机制的读者。
6.1 入口文件
文件位置:packages/core/nest-factory.ts
// NestFactory 是一个单例静态类
export class NestFactoryStatic {
private readonly logger = new Logger('NestFactory', { timestamp: true });
private abortOnError = true;
public async create<T extends INestApplication>(
moduleCls: IEntryNestModule,
serverOrOptions?: AbstractHttpAdapter | NestApplicationOptions,
options?: NestApplicationOptions,
): Promise<T> {
// 1. 解析参数:区分传入的是 httpAdapter 还是 options
const [httpServer, appOptions] = this.isHttpServer(serverOrOptions!)
? [serverOrOptions, options]
: [this.createHttpAdapter(), serverOrOptions];
// 2. 创建应用配置和 DI 容器
const applicationConfig = new ApplicationConfig();
const container = new NestContainer(applicationConfig, appOptions);
// 3. 初始化(扫描 + 实例化 + 注册路由)
await this.initialize(moduleCls, container, ...);
// 4. 创建 NestApplication 实例
const instance = new NestApplication(container, httpServer, ...);
return this.createAdapterProxy<T>(target, httpServer);
}
}
6.2 initialize() — 核心初始化流程
private async initialize(module, container, graphInspector, config, options, httpServer) {
// 1. 创建依赖注入器
const injector = new Injector({ preview: options.preview });
// 2. 创建实例加载器
const instanceLoader = new InstanceLoader(container, injector, graphInspector);
// 3. 创建依赖扫描器
const dependenciesScanner = new DependenciesScanner(container, metadataScanner, graphInspector, config);
// 4. 在异常安全区内执行核心流程
await ExceptionsZone.asyncRun(async () => {
// 4a. 扫描模块树:递归解析 @Module() 的 imports
await dependenciesScanner.scan(module);
// 4b. 实例化所有依赖:按依赖顺序创建 provider 实例
await instanceLoader.createInstancesOfDependencies();
// 4c. 注册全局增强器:APP_GUARD, APP_PIPE, APP_INTERCEPTOR, APP_FILTER
dependenciesScanner.applyApplicationProviders();
});
}
6.3 关键组件职责
NestFactory.create(AppModule)
│
├─→ ApplicationConfig 配置管理(全局前缀、版本控制等)
├─→ NestContainer DI 容器(管理所有模块和提供者)
├─→ DependenciesScanner 模块扫描器(解析 @Module 装饰器)
├─→ InstanceLoader 实例加载器(创建 provider 实例)
├─→ Injector 依赖注入器(解析依赖关系)
├─→ GraphInspector 依赖图检查器(DevTools 用)
├─→ ExceptionsZone 异常安全区(全局 try-catch)
└─→ NestApplication 应用实例(对外暴露 API)
6.4 ExceptionsZone 的作用
ExceptionsZone 是框架的全局异常保护层。create() 返回的 app 对象实际上是一个 Proxy,所有方法调用都被包裹在 ExceptionsZone 中:
// 文件:packages/core/nest-factory.ts
private createProxy(target: any) {
const proxy = this.createExceptionProxy();
return new Proxy(target, { get: proxy, set: proxy });
}
这意味着:
- 框架初始化过程中的任何异常都会被捕获
abortOnError: true(默认)时,未捕获异常导致process.abort()abortOnError: false时,异常会被重新抛出供调用者处理
6.5 MESSAGES 常量
文件位置:packages/core/constants.ts
export const MESSAGES = {
APPLICATION_START: `Starting Nest application...`,
APPLICATION_READY: `Nest application successfully started`,
MICROSERVICE_READY: `Nest microservice successfully started`,
UNKNOWN_EXCEPTION_MESSAGE: 'Internal server error',
};
// 全局增强器注册 token
export const APP_INTERCEPTOR = 'APP_INTERCEPTOR';
export const APP_PIPE = 'APP_PIPE';
export const APP_GUARD = 'APP_GUARD';
export const APP_FILTER = 'APP_FILTER';
启动时看到的 Starting Nest application... 和 Nest application successfully started 日志就来自这里。
七、技术选型与架构定位
[架构] 本节面向技术负责人和架构师。
7.1 NestJS 适用场景
| 场景 | 适合度 | 说明 |
|---|---|---|
| 企业级 REST API | ★★★★★ | 核心场景,模块化 + DI + 管线 |
| 微服务集群 | ★★★★★ | 内置 7 种传输层 + 自定义传输 |
| BFF 层(Backend for Frontend) | ★★★★★ | GraphQL Federation + REST 网关 |
| 全栈应用(MVC) | ★★★★ | 支持模板渲染,但不是主打 |
| WebSocket 实时应用 | ★★★★ | 内置 WebSocket Gateway |
| CLI 工具 | ★★★ | nest-commander 支持 |
| Serverless 函数 | ★★★ | 冷启动开销需要优化 |
| 极简单页 API | ★★ | 过度设计,Express/Fastify 更合适 |
7.2 与其他框架对比
| 特性 | NestJS | Express | Fastify | Spring Boot |
|---|---|---|---|---|
| 语言 | TypeScript | JavaScript | JavaScript | Java |
| 架构 | 约定式(模块+DI) | 自由式 | 自由式 | 约定式(模块+DI) |
| 学习曲线 | 中等 | 低 | 低 | 高 |
| DI 容器 | 内置 | 无 | 无 | 内置(Spring IoC) |
| 微服务 | 内置 | 需自建 | 需自建 | 内置(Spring Cloud) |
| 性能 | 中(Express)/高(Fastify) | 中 | 高 | 中 |
| 生态 | 丰富且增长快 | 最丰富 | 增长中 | 最成熟 |
7.3 团队接入成本评估
有 Angular 经验的团队:几乎零学习成本,概念完全对应 有 Spring Boot 经验的团队:1-2 周适应,核心概念相同 纯 Express 背景的团队:2-4 周适应,主要是 DI 和模块化思维的转变 全新 Node.js 团队:4-6 周,需同时学习 TypeScript + NestJS
八、课后实践
练习 1:创建并运行项目(基础)
nest new cats-api --strict
cd cats-api
npm run start:dev
# 访问 http://localhost:3000 确认 Hello World
练习 2:切换到 Fastify 平台(中阶)
npm i --save @nestjs/platform-fastify
修改 main.ts:
import { NestFactory } from '@nestjs/core';
import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter(),
);
await app.listen(3000, '0.0.0.0');
}
bootstrap();
验证:同样访问 http://localhost:3000 看到 Hello World。
练习 3:使用 SWC 加速编译(中阶)
npm i --save-dev @swc/cli @swc/core
npm run start -- -b swc --watch
对比 tsc 和 SWC 的启动速度差异。
练习 4:探索 CLI 生成器(基础)
# 预览生成结果(不实际创建)
nest g resource cats --dry-run
# 实际生成
nest g resource cats
观察生成的文件结构,理解 NestJS 推荐的代码组织方式。
练习 5:阅读 NestFactory 源码(资深)
打开 packages/core/nest-factory.ts,阅读 create() 和 initialize() 方法,回答:
DependenciesScanner.scan()在什么时候被调用?InstanceLoader.createInstancesOfDependencies()做了什么?ExceptionsZone.asyncRun()为什么要包裹初始化过程?- 为什么返回的
app对象是一个Proxy?
九、本课知识点总结
| 知识点 | 要点 |
|---|---|
| NestJS 定位 | 架构层框架,构建在 Express/Fastify 之上 |
| 核心文件 | main.ts(入口)→ app.module.ts(根模块)→ Controller → Service |
| NestFactory.create() | 创建容器 → 扫描模块 → 实例化依赖 → 注册路由 |
| CLI | nest new(创建), nest g(生成), nest build(编译), nest start(运行) |
| 平台选择 | Express(默认,生态丰富)vs Fastify(高性能) |
| Monorepo | nest g app(子应用), nest g library(共享库) |
| 源码入口 | packages/core/nest-factory.ts → initialize() |
下一课预告:第二课将深入 Controller,学习路由系统、请求参数提取、DTO 定义、版本控制等核心内容。