NestJS 如何配置环境变量

所需依赖

bash 复制代码
pnpm i @nestjs/config js-yaml lodash
pnpm i @types/js-yaml @types/lodash cross-env -D

目录结构

bash 复制代码
|- config
| |- config.yaml # 通用配置文件
| |- config.local.yaml # 通用配置文件本地版(不会被 Git 记录)
| |- config.development.yaml # 开发环境配置文件版
| |- config.development.local.yaml # 开发环境配置文件版(不会被 Git 记录)
| |- config.production.yaml # 生产配置文件本地版
| |- config.production.local.yaml # 生产配置文件本地版(不会被 Git 记录)
|- src
| |- common
|   |- config.module.ts # 自定义的环境配置模块
| |- app.module.ts
|- .gitignore
|- nest-cli.json

涉及文件

1、package.json

json 复制代码
{
  "scripts": {
    "build": "cross-env NODE_ENV=production nest build",
    "start": "cross-env NODE_ENV=development nest start",
    "start:dev": "cross-env NODE_ENV=development nest start --watch",
    "start:debug": "cross-env NODE_ENV=development nest start --debug --watch",
    "start:prod": "node dist/main",
    "start:deploy": "node main.js",
  },
  "dependencies": {
    "@nestjs/config": "^4.0.2",
    "js-yaml": "^4.1.1",
    "lodash": "^4.17.21"
  },
  "devDependencies": {
    "@types/js-yaml": "^4.0.9",
    "@types/lodash": "^4.17.21",
    "cross-env": "^10.1.0"
  }
}

2、config.module.ts

ts 复制代码
import { join } from 'path'
import jsYaml from 'js-yaml'
import { merge } from 'lodash'
import { Module } from '@nestjs/common'
import { readFileSync, existsSync } from 'fs'
import { ConfigModule as NestConfigModule } from '@nestjs/config'

@Module({
  imports: [
    NestConfigModule.forRoot({
      load: [configuration],
      isGlobal: true,
      cache: true,
    }),
  ],
})
export class ConfigModule {}

/**
 * 读取指定路径的 YAML 配置文件并转为对象类型
 * @param filePath YAML 配置文件的路径
 * @returns 解析后的配置对象,如果文件不存在则返回空对象
 */
function loadConfig(filePath: string): Record<string, any> {
  return existsSync(filePath) ? (jsYaml.load(readFileSync(filePath, 'utf-8')) as Record<string, any>) : {}
}

/**
 * 配置加载核心函数:读取并合并多环境 YAML 配置文件
 *
 * 功能说明:
 *  - 根据 NODE_ENV 区分开发/生产环境,确定配置文件存放目录
 *  - 按优先级读取4类 YAML 配置文件(通用→通用本地→环境→环境本地)
 *  - 深度合并配置对象,后续配置会覆盖前面的同名嵌套属性
 *  - 最终返回合并后的完整配置,供 NestJS ConfigModule 使用
 *
 * 配置优先级(从低到高,后面覆盖前面):
 *  - config.yaml < config.local.yaml < config.{NODE_ENV}.yaml < config.{NODE_ENV}.local.yaml
 */
function configuration() {
  // 从环境变量中获取当前运行环境,默认为开发环境
  const { NODE_ENV = 'development' } = process.env

  // 确定配置文件的存放目录
  //  - 开发环境: 读取项目根目录下的 config 文件夹
  //  - 生产环境: 直接读取当前文件所在的目录
  const CONFIG_DIR_PATH = NODE_ENV === 'development' ? join(process.cwd(), 'config') : __dirname

  // 定义各类配置文件的路径
  // 通用配置文件(所有环境共享的基础配置)
  const YAML_COMMON_CONFIG_PATH = join(CONFIG_DIR_PATH, 'config.yaml')
  // 通用本地配置文件(本地开发覆盖通用配置的个性化设置,不应提交到代码仓库)
  const YAML_COMMON_CONFIG_LOCAL_PATH = join(CONFIG_DIR_PATH, 'config.local.yaml')
  // 特定环境的配置文件(针对当前环境的专用配置,如开发/生产环境的差异配置)
  const YAML_ENV_CONFIG_PATH = join(CONFIG_DIR_PATH, `config.${NODE_ENV || 'development'}.yaml`)
  // 特定环境的本地配置文件(本地覆盖当前环境配置的个性化设置,不应提交到代码仓库)
  const YAML_ENV_CONFIG_LOCAL_PATH = join(CONFIG_DIR_PATH, `config.${NODE_ENV || 'development'}.local.yaml`)

  // 读取各类配置文件的内容
  const COMMON_CONFIG = loadConfig(YAML_COMMON_CONFIG_PATH)
  const COMMON_CONFIG_LOCAL = loadConfig(YAML_COMMON_CONFIG_LOCAL_PATH)
  const ENV_CONFIG = loadConfig(YAML_ENV_CONFIG_PATH)
  const ENV_CONFIG_LOCAL = loadConfig(YAML_ENV_CONFIG_LOCAL_PATH)

  // 深度合并配置,后面的配置会覆盖前面的同名配置
  // 这样既保证了基础配置的通用性,又允许环境和本地配置进行个性化定制
  return merge(COMMON_CONFIG, COMMON_CONFIG_LOCAL, ENV_CONFIG, ENV_CONFIG_LOCAL)
}

3、app.module.ts

ts 复制代码
import { Module } from '@nestjs/common'
import { ConfigModule } from './common/config.module.ts'

@Module({
  imports: [ConfigModule]
})
export class AppModule {}

4、.gitignore

bash 复制代码
# dotenv environment variable files
.env.local
*.local.yaml

5、nest-cli.json

json 复制代码
{
  "$schema": "https://json.schemastore.org/nest-cli",
  "collection": "@nestjs/schematics",
  "sourceRoot": "src",
  "compilerOptions": {
    "assets": [
      { "include": "../package.json", "outDir": "./dist/package.json" },
      { "include": "../pnpm-lock.yaml", "outDir": "./dist/pnpm-lock.yaml" },
      { "include": "../config/config.yaml", "outDir": "./dist" }
    ],
    "deleteOutDir": true,
    "builder": "webpack"
  },
  "generateOptions": {
    "flat": false,
    "spec": false
  }
}

使用介绍

1、service 服务使用

ts 复制代码
import { Injectable } from '@nestjs/common'
import { ConfigService } from '@nestjs/config'

@Injectable()
export class LoginService {
  constructor(private readonly configService: ConfigService) {}
  
  public testEnvConfig() {
    const dbHost = this.configService.get<string>('database.host','localhost')
  }
}

2、main.ts 中使用

ts 复制代码
import { AppModule } from './app.module'
import { ConfigService } from '@nestjs/config'

async function bootstrap() {
  const app = await NestFactory.create(AppModule)
  
  // 从应用容器中获取配置服务实例,由于 ConfigModule 被设置为全局模块,这里可以直接获取
  const configService = app.get(ConfigService)
  const serverPort = configService.get<number>('server.port', 3000)
  
  // 启动应用并监听配置中指定的端口
  // 这一步会启动 HTTP 服务器,使应用开始接收外部请求
  await app.listen(serverPort)
  
  // 打印服务启动信息,方便开发者在终端查看访问地址
  console.log('\n--------------------------------------------------')
  console.log(`➜  Local:    http://localhost:${serverPort}`)
  console.log('--------------------------------------------------')
}

// 调用启动函数,启动应用
bootstrap()
相关推荐
濮水大叔12 天前
VonaJS是如何做到文件级别精确HMR(热更新)的?
typescript·node.js·nestjs
ovensi12 天前
告别笨重的 ELK,拥抱轻量级 PLG:NestJS 日志监控实战指南
nestjs
ovensi13 天前
Docker+NestJS+ELK:从零搭建全链路日志监控系统
后端·nestjs
Gogo81615 天前
nestjs 的项目启动
nestjs
没头发的卓卓1 个月前
新手入门:nest基本使用规则(适合零基础小白)
nestjs
孟祥_成都1 个月前
深入 Nestjs 底层概念(1):依赖注入和面向切面编程 AOP
前端·node.js·nestjs
濮水大叔1 个月前
VonaJS: 基于winston的Logger日志系统
typescript·nodejs·nestjs