项目初始化
本节将配置模块、日志模块和异常过滤器整合到一个 NestJS 模板项目中,作为后续业务开发的基础骨架。
# 创建项目
pnpm @nestjs/new nestjs-starter --package-manager pnpm
# 安装配置相关依赖
pnpm add @nestjs/config joi
pnpm add cross-env
bash
当前版本参考:@nestjs/config@3.2.x、joi@17.x。
清理默认文件
NestJS CLI 生成的项目包含一些模板文件,在模板项目中需要清理:
- 删除
app.service.ts及其在app.module.ts中的引用 - 保留
app.controller.ts中的getHello()方法用于后续测试 - 删除不需要的模板文件
配置模块设置
环境文件
创建 .env(默认配置)和 .env.development(开发环境覆盖):
# .env
DB_HOST=127.0.0.1
# .env.development
PORT=3300
bash
ConfigModule.forRoot 配置
// app.module.ts
import { ConfigModule } from '@nestjs/config';
import * as Joi from 'joi';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
envFilePath: [`.env.${process.env.NODE_ENV || 'development'}`, '.env'],
load: [],
validationSchema: Joi.object({
NODE_ENV: Joi.string()
.valid('development', 'production', 'test')
.default('development'),
PORT: Joi.number().default(3000),
DB_HOST: Joi.string().default('127.0.0.1'),
}),
}),
],
})
export class AppModule {}
typescript
| 选项 | 说明 |
|---|---|
isGlobal: true | 全局注册,其他模块无需重复 import |
envFilePath | 按优先级加载环境文件,先加载环境特定文件,再加载默认文件 |
validationSchema | Joi 校验规则,启动时自动验证环境变量 |
validationOptions | 可选:{ allowUnknown: false, abortEarly: true } |
在 main.ts 中读取配置
main.ts 中需要通过 app.get(ConfigService) 获取配置:
// main.ts
import { ConfigService } from '@nestjs/config';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const configService = app.get(ConfigService);
const port = configService.get<number>('PORT', 3000);
await app.listen(port);
console.log(`Application running on port ${port}`);
}
bootstrap();
typescript
启动脚本配置
在 package.json 中配置多环境启动命令:
{
"scripts": {
"start:dev": "cross-env NODE_ENV=development nest start --watch",
"start:prod": "cross-env NODE_ENV=production node dist/main"
}
}
json
cross-env 解决跨平台(Windows/macOS/Linux)环境变量设置兼容性问题。
封装为独立模块
将配置逻辑从 AppModule 抽离到 common/config/config.module.ts,保持 AppModule 简洁:
// common/config/config.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule as NestConfigModule } from '@nestjs/config';
import * as Joi from 'joi';
@Module({
imports: [
NestConfigModule.forRoot({
isGlobal: true,
envFilePath: [`.env.${process.env.NODE_ENV || 'development'}`, '.env'],
validationSchema: Joi.object({
NODE_ENV: Joi.string().valid('development', 'production', 'test').default('development'),
PORT: Joi.number().default(3000),
DB_HOST: Joi.string().default('127.0.0.1'),
}),
}),
],
})
export class AppConfigModule {}
typescript
// app.module.ts
import { AppConfigModule } from './common/config/config.module';
@Module({
imports: [AppConfigModule],
})
export class AppModule {}
typescript
注意自定义模块名避免与官方
ConfigModule冲突,此处命名为AppConfigModule。
依赖版本注意事项
更新依赖时注意 ESLint 兼容性:
# 检查可更新的依赖
npx npm-check -u
# ESLint 9 与 @typescript-eslint 插件可能不兼容,锁定到 8.x
pnpm add -D eslint@8.56.0
bash
更新完成后删除 node_modules 重新安装,确保依赖树一致。
↑