NestJS开发工具扩展
NestJS开发工具扩展
学习目标:掌握 SWC 编译器的使用和 REPL 开发模式,提升开发效率。
一、SWC 编译器
1.1 SWC 简介
什么是 SWC?
SWC(Speedy Web Compiler)是一个基于 Rust 语言编写的超快速 JavaScript/TypeScript 编译器。
SWC 特点:
SWC 优势:
│
├── 极快的编译速度
│ ├── 基于 Rust 语言开发
│ ├── 比 TSC 快 20 倍以上
│ └── 单线程性能强劲
│
├── 功能丰富
│ ├── 编译 TypeScript/JavaScript
│ ├── 代码压缩(Minification)
│ ├── 代码打包(Bundling)
│ └── 代码转换(Transpilation)
│
├── NestJS 10+ 原生支持
│ ├── 官方集成
│ ├── 配置简单
│ └── 无缝替换 TSC
│
└── 社区活跃
├── 持续更新
├── 问题修复快
└── 生态完善性能对比:
| 编译器 | 编译时间 | 性能提升 |
|---|---|---|
| TSC(TypeScript Compiler) | 602ms | 基准 |
| SWC | 177ms | 快 3.4 倍(约 340%) |
1.2 安装依赖
# 安装 SWC 相关依赖
pnpm install @swc/cli @swc/core
# 或使用 npm
npm install @swc/cli @swc/core
# 或使用 yarn
yarn add @swc/cli @swc/core依赖说明:
| 包名 | 作用 |
|---|---|
@swc/cli | SWC 命令行工具 |
@swc/core | SWC 核心编译器 |
1.3 性能测试
测试代码:
src/main.ts:
const startTime = new Date().getTime();
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
console.log(
'First boot time:',
new Date().getTime() - startTime,
'ms'
);
}
bootstrap();测试结果:
# 使用默认 TSC 编译器
$ pnpm start:dev
First boot time: 602ms
# 使用 SWC 编译器
$ pnpm start:dev -b swc
First boot time: 177ms性能提升:快了约 3.4 倍(340%)
1.4 基础使用方式
方式一:命令行参数
package.json:
{
"scripts": {
"start": "nest start -b swc",
"start:dev": "nest start --watch -b swc",
"start:debug": "nest start --debug --watch -b swc",
"start:prod": "node dist/main"
}
}参数说明:
-b swc:指定使用 SWC 编译器--watch:监听文件变化--debug:开启调试模式
1.5 配置 SWC 为默认编译器
步骤一:创建 SWC 配置文件
.swcrc:
{
"jsc": {
"parser": {
"syntax": "typescript",
"decorators": true,
"dynamicImport": true
},
"transform": {
"legacyDecorator": true,
"decoratorMetadata": true
},
"target": "es2021",
"keepClassNames": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"minify": true,
"module": {
"type": "commonjs"
}
}配置项说明:
| 配置项 | 作用 | 说明 |
|---|---|---|
jsc.parser.syntax | 语法类型 | typescript 支持装饰器 |
jsc.transform.legacyDecorator | 装饰器模式 | true 启用旧版装饰器 |
jsc.transform.decoratorMetadata | 装饰器元数据 | true 启用元数据支持 |
jsc.target | 编译目标 | es2021 现代浏览器 |
minify | 代码压缩 | true 启用压缩 |
module.type | 模块类型 | commonjs Node.js 模块 |
paths | 路径别名 | 类似 TypeScript 的 paths |
步骤二:修改 nest-cli.json
nest-cli.json:
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"builder": "swc",
"typeCheck": true
}
}配置说明:
builder: "swc":设置 SWC 为默认编译器typeCheck: true:启用类型检查(可选)
步骤三:验证配置
# 构建项目
$ pnpm build
# 查看输出日志
SWC running... # 出现此日志表示使用 SWC 编译器
# 启动开发服务器
$ pnpm start:dev
SWC running... # 出现此日志表示使用 SWC 编译器构建产物:
# 查看构建后的代码
$ cat dist/main.js
# SWC 构建的代码是压缩过的
!function(){"use strict";...}();1.6 SWC vs TSC 对比
| 维度 | TSC | SWC |
|---|---|---|
| 编译速度 | 慢 | 快 3-4 倍 |
| 类型检查 | 完整支持 | 不支持(需额外配置) |
| 装饰器 | 完整支持 | 支持 |
| 路径别名 | 完整支持 | 部分支持(有问题) |
| Source Map | 完整支持 | 支持 |
| 代码压缩 | 不支持 | 支持 |
| 配置复杂度 | 简单 | 中等 |
| 稳定性 | 非常稳定 | 较稳定 |
1.7 SWC 已知问题
问题一:路径别名(Path Aliases)不支持
问题描述:
- SWC 对 TypeScript 的
paths配置支持不完善 - 可能导致模块导入失败
解决方案:
// 可能失败的路径别名导入
import { UserService } from '@user/user.service';
// 使用相对路径导入
import { UserService } from './user/user.service';问题二:装饰器元数据问题
问题描述:
- 某些情况下装饰器元数据可能丢失
解决方案:
// .swcrc
{
"jsc": {
"transform": {
"legacyDecorator": true,
"decoratorMetadata": true // 确保开启
}
}
}问题三:类型检查缺失
问题描述:
- SWC 不进行类型检查,只进行编译
解决方案:
# 方案 1:在 nest-cli.json 中启用类型检查
{
"compilerOptions": {
"builder": "swc",
"typeCheck": true // 启用类型检查
}
}
# 方案 2:单独运行类型检查
$ pnpm tsc --noEmit1.8 回退到 TSC
如果 SWC 出现问题,可以回退到 TSC:
nest-cli.json:
{
"compilerOptions": {
"builder": "tsc" // 改回 tsc
}
}或使用命令行:
# 临时使用 TSC
$ pnpm start:dev -b tsc
# 或使用 webpack
$ pnpm start:dev -b webpack1.9 SWC 最佳实践
开发环境推荐:
开发环境配置建议:
│
├── 使用 SWC 编译器
│ ├── 编译速度快
│ ├── 开发体验好
│ └── 热重载快
│
├── 启用类型检查
│ ├── nest-cli.json 中设置 typeCheck: true
│ └── 或单独运行 tsc --noEmit
│
└── 注意路径别名
├── 优先使用相对路径
└── 或等待官方修复生产环境推荐:
生产环境配置建议:
│
├── 使用 TSC 编译器
│ ├── 类型检查完整
│ ├── 稳定性高
│ └── 兼容性好
│
└── 启用代码压缩
├── 使用 SWC 的 minify 功能
└── 或使用其他压缩工具二、REPL 模式
2.1 REPL 简介
什么是 REPL?
REPL(Read-Eval-Print Loop)即"读取-求值-输出-循环",是一个交互式编程环境。
REPL 功能:
REPL 功能:
│
├── 检查依赖图
│ ├── 查看所有 Controllers
│ ├── 查看所有 Providers
│ └── 查看模块依赖关系
│
├── 调用控制器方法
│ ├── 直接调用 Controller 方法
│ ├── 测试接口逻辑
│ └── 快速验证功能
│
├── 调用服务方法
│ ├── 直接调用 Service 方法
│ ├── 测试业务逻辑
│ └── 调试数据处理
│
└── 实时交互
├── 命令行交互
├── 实时输出结果
└── 快速原型开发2.2 启用 REPL 模式
方法一:在 main.ts 中集成
src/main.ts:
import { NestFactory } from '@nestjs/core';
import { repl } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
// 启用 REPL 模式
repl(AppModule);
bootstrap();方法二:创建独立的 REPL 文件
src/repl.ts:
import { repl } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
await repl(AppModule);
}
bootstrap();package.json:
{
"scripts": {
"start:dev": "nest start --watch",
"repl": "ts-node -r tsconfig-paths/register src/repl.ts"
}
}运行 REPL:
# 运行 REPL 模式
$ pnpm repl
# 或
$ npm run repl2.3 REPL 常用命令
基础命令:
# 查看 debug 信息
> debug()
{
controllers: [
{
name: 'AppController',
dependencies: [ 'AppService' ]
}
],
providers: [
{
name: 'AppService',
dependencies: []
}
],
modules: [
{
name: 'AppModule',
imports: [],
controllers: [ 'AppController' ],
providers: [ 'AppService' ]
}
]
}查看可用的方法:
# 查看所有公共方法
> methods()
[
'debug',
'methods',
'get',
'select',
'resolve',
'watch'
]获取模块实例:
# 获取 AppController 实例
> get(AppController)
AppController {}
# 获取 AppService 实例
> get(AppService)
AppService {}调用方法:
# 调用 Controller 方法
> get(AppController).getHello()
'Hello World!'
# 调用 Service 方法
> get(AppService).findAll()
[ { id: 1, name: 'User 1' }, { id: 2, name: 'User 2' } ]选择特定模块:
# 选择模块
> select(AppModule)
AppModule {}
# 选择后直接调用方法
> select(AppModule).get(AppController).getHello()
'Hello World!'解析依赖:
# 解析提供者
> resolve(AppService)
AppService {}2.4 REPL 实战示例
示例一:测试 Controller
// src/app.controller.ts
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
@Get('users')
getUsers() {
return this.appService.getUsers();
}
}REPL 测试:
$ pnpm repl
# 查看 debug 信息
> debug()
# 获取 Controller 实例
> const appController = get(AppController)
# 调用方法
> appController.getHello()
'Hello World!'
> appController.getUsers()
[ { id: 1, name: 'User 1' } ]示例二:测试 Service
// src/user/user.service.ts
@Injectable()
export class UserService {
private users = [
{ id: 1, name: 'User 1', email: 'user1@example.com' },
{ id: 2, name: 'User 2', email: 'user2@example.com' },
];
findAll() {
return this.users;
}
findOne(id: number) {
return this.users.find(user => user.id === id);
}
create(userData: any) {
const newUser = { id: this.users.length + 1, ...userData };
this.users.push(newUser);
return newUser;
}
}REPL 测试:
$ pnpm repl
# 获取 Service 实例
> const userService = get(UserService)
# 查询所有用户
> userService.findAll()
[ { id: 1, name: 'User 1' }, { id: 2, name: 'User 2' } ]
# 查询单个用户
> userService.findOne(1)
{ id: 1, name: 'User 1', email: 'user1@example.com' }
# 创建用户
> userService.create({ name: 'User 3', email: 'user3@example.com' })
{ id: 3, name: 'User 3', email: 'user3@example.com' }
# 再次查询
> userService.findAll()
[
{ id: 1, name: 'User 1' },
{ id: 2, name: 'User 2' },
{ id: 3, name: 'User 3' }
]示例三:测试数据库操作
// src/prisma/prisma.service.ts
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
async onModuleInit() {
await this.$connect();
}
}
// src/user/user.service.ts
@Injectable()
export class UserService {
constructor(private prisma: PrismaService) {}
async findAll() {
return this.prisma.user.findMany();
}
async create(data: CreateUserDto) {
return this.prisma.user.create({ data });
}
}REPL 测试:
$ pnpm repl
# 获取 Service 实例
> const userService = get(UserService)
# 异步查询所有用户
> await userService.findAll()
[ { id: 1, name: 'User 1' }, { id: 2, name: 'User 2' } ]
# 异步创建用户
> await userService.create({ name: 'User 3', email: 'user3@example.com' })
{ id: 3, name: 'User 3', email: 'user3@example.com' }2.5 REPL 命令详解
| 命令 | 作用 | 示例 |
|---|---|---|
debug() | 查看依赖图和模块信息 | debug() |
methods() | 查看所有可用方法 | methods() |
get(Class) | 获取类实例 | get(AppController) |
select(Module) | 选择模块 | select(AppModule) |
resolve(Provider) | 解析提供者 | resolve(AppService) |
watch() | 监听文件变化 | watch() |
2.6 REPL vs HTTP 请求对比
| 维度 | REPL | HTTP 请求 |
|---|---|---|
| 启动速度 | 快 | 需要启动服务器 |
| 调试效率 | 高(直接调用) | 中(需要发送请求) |
| 测试范围 | 所有方法 | 仅 Controller 方法 |
| 使用场景 | 开发调试 | 接口测试 |
| 依赖注入 | 自动处理 | 需要手动处理 |
| 实时反馈 | 即时 | 需要工具 |
2.7 REPL 最佳实践
适合 REPL 的场景:
REPL 适用场景:
│
├── 快速原型开发
│ ├── 测试业务逻辑
│ ├── 验证数据处理
│ └── 调试算法实现
│
├── 调试依赖注入
│ ├── 检查依赖关系
│ ├── 验证实例化
│ └── 调试模块加载
│
├── 数据库操作测试
│ ├── 测试查询语句
│ ├── 验证数据映射
│ └── 调试事务处理
│
└── 快速验证功能
├── 测试 Service 方法
├── 验证工具函数
└── 调试复杂逻辑不适合 REPL 的场景:
不适合 REPL 的场景:
│
├── 性能测试
│ └── REPL 环境与生产环境不同
│
├── 集成测试
│ └── 需要完整的 HTTP 环境
│
└── 端到端测试
└── 需要完整的应用流程三、NestJS 社区资源
3.1 GitHub Issues
查看和报告问题:
- 地址:https://github.com/nestjs/nest/issues
- 用途:
- 查看已知问题
- 报告新问题
- 参与讨论
常见问题分类:
NestJS Issues 分类:
│
├── Bug Reports
│ ├── 编译错误
│ ├── 运行时错误
│ └── 类型错误
│
├── Feature Requests
│ ├── 新功能建议
│ ├── API 改进
│ └── 性能优化
│
├── Questions
│ ├── 使用问题
│ ├── 配置问题
│ └── 最佳实践
│
└── Documentation
├── 文档错误
├── 文档改进
└── 示例代码3.2 Discord 社区
加入 Discord:
- 地址:https://discord.gg/nestjs
- 用途:
- 实时交流
- 快速获得帮助
- 社区互动
社区频道:
Discord 频道:
│
├── #nestjs-help
│ ├── 使用问题
│ ├── 快速答疑
│ └── 新手入门
│
├── #nestjs-core
│ ├── 核心功能
│ ├── 架构讨论
│ └── 深度交流
│
├── #nestjs-orm
│ ├── TypeORM
│ ├── Prisma
│ └── 数据库相关
│
└── #nestjs-graphql
├── GraphQL 集成
├── Apollo
└── 查询优化识别官方成员:
- 狮子图标 = Core Team 成员
- 这些成员是 NestJS 核心团队成员,可以优先咨询
3.3 版本更新
检查和更新依赖:
# 检查过期依赖
$ pnpm outdated
# 交互式更新
$ pnpm update -i
# 或使用 npm
$ npm outdated
$ npm update更新 NestJS CLI:
# 更新全局 CLI
$ pnpm update -g @nestjs/cli
# 或使用 npm
$ npm update -g @nestjs/cli版本更新策略:
版本更新建议:
│
├── 小版本更新(1.0.0 → 1.0.1)
│ ├── Bug 修复
│ ├── 安全补丁
│ └── 可以直接更新
│
├── 中版本更新(1.0.0 → 1.1.0)
│ ├── 新功能
│ ├── 向后兼容
│ └── 可以直接更新
│
└── 大版本更新(1.0.0 → 2.0.0)
├── 破坏性变更
├── 需要迁移
└── 谨慎更新四、完整配置示例
4.1 项目结构
project/
├── src/
│ ├── main.ts
│ ├── repl.ts # REPL 配置
│ ├── app.module.ts
│ └── ...
├── .swcrc # SWC 配置
├── nest-cli.json # NestJS CLI 配置
├── tsconfig.json # TypeScript 配置
└── package.json4.2 完整配置文件
nest-cli.json:
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"builder": "swc",
"typeCheck": true
}
}.swcrc:
{
"jsc": {
"parser": {
"syntax": "typescript",
"decorators": true,
"dynamicImport": true
},
"transform": {
"legacyDecorator": true,
"decoratorMetadata": true
},
"target": "es2021",
"keepClassNames": true
},
"minify": false,
"module": {
"type": "commonjs"
}
}package.json:
{
"scripts": {
"build": "nest build",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"repl": "ts-node -r tsconfig-paths/register src/repl.ts",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@nestjs/common": "^10.0.0",
"@nestjs/core": "^10.0.0",
"@nestjs/platform-express": "^10.0.0",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1"
},
"devDependencies": {
"@nestjs/cli": "^10.0.0",
"@swc/cli": "^0.1.62",
"@swc/core": "^1.3.68",
"@types/node": "^20.3.1",
"typescript": "^5.1.3"
}
}src/repl.ts:
import { repl } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
await repl(AppModule);
}
bootstrap();4.3 使用流程
# 1. 安装依赖
$ pnpm install
# 2. 开发模式启动(使用 SWC)
$ pnpm start:dev
# 3. 启动 REPL 模式
$ pnpm repl
# 4. 构建生产版本
$ pnpm build
# 5. 运行类型检查
$ pnpm typecheck五、学习要点总结
5.1 核心概念速记
NestJS 开发工具扩展核心概念:
│
├── SWC 编译器
│ ├── 基于 Rust 开发
│ ├── 比 TSC 快 3-4 倍
│ ├── NestJS 10+ 原生支持
│ ├── 配置:nest-cli.json 中设置 builder: "swc"
│ ├── 已知问题:路径别名支持不完善
│ └── 建议:开发环境用 SWC,生产环境用 TSC
│
└── REPL 模式
├── Read-Eval-Print Loop
├── 交互式编程环境
├── 功能:查看依赖图、调用方法、调试代码
├── 命令:debug()、get()、methods()、select()
└── 场景:快速原型开发、调试依赖注入5.2 重点知识清单
| 知识点 | 重要程度 | 掌握程度 |
|---|---|---|
| SWC 的作用和优势 | 未掌握 / 已掌握 | |
| SWC 安装和配置 | 未掌握 / 已掌握 | |
| SWC 性能对比 | 未掌握 / 已掌握 | |
| SWC 已知问题 | 未掌握 / 已掌握 | |
| REPL 的作用 | 未掌握 / 已掌握 | |
| REPL 常用命令 | 未掌握 / 已掌握 | |
| REPL 实战应用 | 未掌握 / 已掌握 | |
| NestJS 社区资源 | 未掌握 / 已掌握 |
5.3 课后思考题
- SWC 相比 TSC 有什么优势?
- 如何在 NestJS 中配置 SWC 为默认编译器?
- SWC 有哪些已知问题?如何解决?
- REPL 模式有什么作用?适合什么场景?
- 如何在 REPL 中调用 Controller 和 Service 方法?