{T}

NestJS开发工具扩展

NestJS开发工具扩展

学习目标:掌握 SWC 编译器的使用和 REPL 开发模式,提升开发效率。


一、SWC 编译器

1.1 SWC 简介

什么是 SWC?

SWC(Speedy Web Compiler)是一个基于 Rust 语言编写的超快速 JavaScript/TypeScript 编译器。

SWC 特点

code
SWC 优势:
│
├── 极快的编译速度
│   ├── 基于 Rust 语言开发
│   ├── 比 TSC 快 20 倍以上
│   └── 单线程性能强劲
│
├── 功能丰富
│   ├── 编译 TypeScript/JavaScript
│   ├── 代码压缩(Minification)
│   ├── 代码打包(Bundling)
│   └── 代码转换(Transpilation)
│
├── NestJS 10+ 原生支持
│   ├── 官方集成
│   ├── 配置简单
│   └── 无缝替换 TSC
│
└── 社区活跃
    ├── 持续更新
    ├── 问题修复快
    └── 生态完善

性能对比

编译器编译时间性能提升
TSC(TypeScript Compiler)602ms基准
SWC177ms快 3.4 倍(约 340%)

1.2 安装依赖

bash
# 安装 SWC 相关依赖
pnpm install @swc/cli @swc/core

# 或使用 npm
npm install @swc/cli @swc/core

# 或使用 yarn
yarn add @swc/cli @swc/core

依赖说明

包名作用
@swc/cliSWC 命令行工具
@swc/coreSWC 核心编译器

1.3 性能测试

测试代码

src/main.ts

typescript
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();

测试结果

bash
# 使用默认 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

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

json
{
  "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

json
{
  "$schema": "https://json.schemastore.org/nest-cli",
  "collection": "@nestjs/schematics",
  "sourceRoot": "src",
  "compilerOptions": {
    "builder": "swc",
    "typeCheck": true
  }
}

配置说明

  • builder: "swc":设置 SWC 为默认编译器
  • typeCheck: true:启用类型检查(可选)

步骤三:验证配置

bash
# 构建项目
$ pnpm build

# 查看输出日志
SWC running...  # 出现此日志表示使用 SWC 编译器

# 启动开发服务器
$ pnpm start:dev
SWC running...  # 出现此日志表示使用 SWC 编译器

构建产物

bash
# 查看构建后的代码
$ cat dist/main.js

# SWC 构建的代码是压缩过的
!function(){"use strict";...}();

1.6 SWC vs TSC 对比

维度TSCSWC
编译速度快 3-4 倍
类型检查完整支持不支持(需额外配置)
装饰器完整支持支持
路径别名完整支持部分支持(有问题)
Source Map完整支持支持
代码压缩不支持支持
配置复杂度简单中等
稳定性非常稳定较稳定

1.7 SWC 已知问题

问题一:路径别名(Path Aliases)不支持

问题描述

  • SWC 对 TypeScript 的 paths 配置支持不完善
  • 可能导致模块导入失败

解决方案

typescript
//  可能失败的路径别名导入
import { UserService } from '@user/user.service';

//  使用相对路径导入
import { UserService } from './user/user.service';

问题二:装饰器元数据问题

问题描述

  • 某些情况下装饰器元数据可能丢失

解决方案

json
// .swcrc
{
  "jsc": {
    "transform": {
      "legacyDecorator": true,
      "decoratorMetadata": true  // 确保开启
    }
  }
}

问题三:类型检查缺失

问题描述

  • SWC 不进行类型检查,只进行编译

解决方案

bash
# 方案 1:在 nest-cli.json 中启用类型检查
{
  "compilerOptions": {
    "builder": "swc",
    "typeCheck": true  // 启用类型检查
  }
}

# 方案 2:单独运行类型检查
$ pnpm tsc --noEmit

1.8 回退到 TSC

如果 SWC 出现问题,可以回退到 TSC

nest-cli.json

json
{
  "compilerOptions": {
    "builder": "tsc"  // 改回 tsc
  }
}

或使用命令行

bash
# 临时使用 TSC
$ pnpm start:dev -b tsc

# 或使用 webpack
$ pnpm start:dev -b webpack

1.9 SWC 最佳实践

开发环境推荐

code
开发环境配置建议:
│
├── 使用 SWC 编译器
│   ├── 编译速度快
│   ├── 开发体验好
│   └── 热重载快
│
├── 启用类型检查
│   ├── nest-cli.json 中设置 typeCheck: true
│   └── 或单独运行 tsc --noEmit
│
└── 注意路径别名
    ├── 优先使用相对路径
    └── 或等待官方修复

生产环境推荐

code
生产环境配置建议:
│
├── 使用 TSC 编译器
│   ├── 类型检查完整
│   ├── 稳定性高
│   └── 兼容性好
│
└── 启用代码压缩
    ├── 使用 SWC 的 minify 功能
    └── 或使用其他压缩工具

二、REPL 模式

2.1 REPL 简介

什么是 REPL?

REPL(Read-Eval-Print Loop)即"读取-求值-输出-循环",是一个交互式编程环境。

REPL 功能

code
REPL 功能:
│
├── 检查依赖图
│   ├── 查看所有 Controllers
│   ├── 查看所有 Providers
│   └── 查看模块依赖关系
│
├── 调用控制器方法
│   ├── 直接调用 Controller 方法
│   ├── 测试接口逻辑
│   └── 快速验证功能
│
├── 调用服务方法
│   ├── 直接调用 Service 方法
│   ├── 测试业务逻辑
│   └── 调试数据处理
│
└── 实时交互
    ├── 命令行交互
    ├── 实时输出结果
    └── 快速原型开发

2.2 启用 REPL 模式

方法一:在 main.ts 中集成

src/main.ts

typescript
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

typescript
import { repl } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  await repl(AppModule);
}
bootstrap();

package.json

json
{
  "scripts": {
    "start:dev": "nest start --watch",
    "repl": "ts-node -r tsconfig-paths/register src/repl.ts"
  }
}

运行 REPL

bash
# 运行 REPL 模式
$ pnpm repl

# 或
$ npm run repl

2.3 REPL 常用命令

基础命令

bash
# 查看 debug 信息
> debug()
{
  controllers: [
    {
      name: 'AppController',
      dependencies: [ 'AppService' ]
    }
  ],
  providers: [
    {
      name: 'AppService',
      dependencies: []
    }
  ],
  modules: [
    {
      name: 'AppModule',
      imports: [],
      controllers: [ 'AppController' ],
      providers: [ 'AppService' ]
    }
  ]
}

查看可用的方法

bash
# 查看所有公共方法
> methods()
[
  'debug',
  'methods',
  'get',
  'select',
  'resolve',
  'watch'
]

获取模块实例

bash
# 获取 AppController 实例
> get(AppController)
AppController {}

# 获取 AppService 实例
> get(AppService)
AppService {}

调用方法

bash
# 调用 Controller 方法
> get(AppController).getHello()
'Hello World!'

# 调用 Service 方法
> get(AppService).findAll()
[ { id: 1, name: 'User 1' }, { id: 2, name: 'User 2' } ]

选择特定模块

bash
# 选择模块
> select(AppModule)
AppModule {}

# 选择后直接调用方法
> select(AppModule).get(AppController).getHello()
'Hello World!'

解析依赖

bash
# 解析提供者
> resolve(AppService)
AppService {}

2.4 REPL 实战示例

示例一:测试 Controller

typescript
// 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 测试

bash
$ pnpm repl

# 查看 debug 信息
> debug()

# 获取 Controller 实例
> const appController = get(AppController)

# 调用方法
> appController.getHello()
'Hello World!'

> appController.getUsers()
[ { id: 1, name: 'User 1' } ]

示例二:测试 Service

typescript
// 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 测试

bash
$ 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' }
]

示例三:测试数据库操作

typescript
// 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 测试

bash
$ 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 请求对比

维度REPLHTTP 请求
启动速度需要启动服务器
调试效率高(直接调用)中(需要发送请求)
测试范围所有方法仅 Controller 方法
使用场景开发调试接口测试
依赖注入自动处理需要手动处理
实时反馈即时需要工具

2.7 REPL 最佳实践

适合 REPL 的场景

code
REPL 适用场景:
│
├── 快速原型开发
│   ├── 测试业务逻辑
│   ├── 验证数据处理
│   └── 调试算法实现
│
├── 调试依赖注入
│   ├── 检查依赖关系
│   ├── 验证实例化
│   └── 调试模块加载
│
├── 数据库操作测试
│   ├── 测试查询语句
│   ├── 验证数据映射
│   └── 调试事务处理
│
└── 快速验证功能
    ├── 测试 Service 方法
    ├── 验证工具函数
    └── 调试复杂逻辑

不适合 REPL 的场景

code
不适合 REPL 的场景:
│
├── 性能测试
│   └── REPL 环境与生产环境不同
│
├── 集成测试
│   └── 需要完整的 HTTP 环境
│
└── 端到端测试
    └── 需要完整的应用流程

三、NestJS 社区资源

3.1 GitHub Issues

查看和报告问题

常见问题分类

code
NestJS Issues 分类:
│
├── Bug Reports
│   ├── 编译错误
│   ├── 运行时错误
│   └── 类型错误
│
├── Feature Requests
│   ├── 新功能建议
│   ├── API 改进
│   └── 性能优化
│
├── Questions
│   ├── 使用问题
│   ├── 配置问题
│   └── 最佳实践
│
└── Documentation
    ├── 文档错误
    ├── 文档改进
    └── 示例代码

3.2 Discord 社区

加入 Discord

社区频道

code
Discord 频道:
│
├── #nestjs-help
│   ├── 使用问题
│   ├── 快速答疑
│   └── 新手入门
│
├── #nestjs-core
│   ├── 核心功能
│   ├── 架构讨论
│   └── 深度交流
│
├── #nestjs-orm
│   ├── TypeORM
│   ├── Prisma
│   └── 数据库相关
│
└── #nestjs-graphql
    ├── GraphQL 集成
    ├── Apollo
    └── 查询优化

识别官方成员

  • 狮子图标 = Core Team 成员
  • 这些成员是 NestJS 核心团队成员,可以优先咨询

3.3 版本更新

检查和更新依赖

bash
# 检查过期依赖
$ pnpm outdated

# 交互式更新
$ pnpm update -i

# 或使用 npm
$ npm outdated
$ npm update

更新 NestJS CLI

bash
# 更新全局 CLI
$ pnpm update -g @nestjs/cli

# 或使用 npm
$ npm update -g @nestjs/cli

版本更新策略

code
版本更新建议:
│
├── 小版本更新(1.0.0 → 1.0.1)
│   ├── Bug 修复
│   ├── 安全补丁
│   └── 可以直接更新
│
├── 中版本更新(1.0.0 → 1.1.0)
│   ├── 新功能
│   ├── 向后兼容
│   └── 可以直接更新
│
└── 大版本更新(1.0.0 → 2.0.0)
    ├── 破坏性变更
    ├── 需要迁移
    └── 谨慎更新

四、完整配置示例

4.1 项目结构

code
project/
├── src/
│   ├── main.ts
│   ├── repl.ts              # REPL 配置
│   ├── app.module.ts
│   └── ...
├── .swcrc                   # SWC 配置
├── nest-cli.json            # NestJS CLI 配置
├── tsconfig.json            # TypeScript 配置
└── package.json

4.2 完整配置文件

nest-cli.json

json
{
  "$schema": "https://json.schemastore.org/nest-cli",
  "collection": "@nestjs/schematics",
  "sourceRoot": "src",
  "compilerOptions": {
    "builder": "swc",
    "typeCheck": true
  }
}

.swcrc

json
{
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "decorators": true,
      "dynamicImport": true
    },
    "transform": {
      "legacyDecorator": true,
      "decoratorMetadata": true
    },
    "target": "es2021",
    "keepClassNames": true
  },
  "minify": false,
  "module": {
    "type": "commonjs"
  }
}

package.json

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

typescript
import { repl } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  await repl(AppModule);
}
bootstrap();

4.3 使用流程

bash
# 1. 安装依赖
$ pnpm install

# 2. 开发模式启动(使用 SWC)
$ pnpm start:dev

# 3. 启动 REPL 模式
$ pnpm repl

# 4. 构建生产版本
$ pnpm build

# 5. 运行类型检查
$ pnpm typecheck

五、学习要点总结

5.1 核心概念速记

code
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 课后思考题

  1. SWC 相比 TSC 有什么优势?
  2. 如何在 NestJS 中配置 SWC 为默认编译器?
  3. SWC 有哪些已知问题?如何解决?
  4. REPL 模式有什么作用?适合什么场景?
  5. 如何在 REPL 中调用 Controller 和 Service 方法?

参考资料


上一章23-NestJS日志系统与Winston集成

下一章25-NestJS配置管理与环境变量