经验分享
Nest环境变量配置
使用nest start开发环境启动项目,使用pm2生产环境启动,如何定义环境变量,如何区分环境变量配置,本文带你了解~
2024-01-11 14:09:08
40

原理:nestjs 会识别到项目根目录的 .env 文件中的变量,并将其添加在 process.env 下,我们只需要在不同环境中给 .env 中写入不同环境标识即可。

定义脚本文件

src/scripts 中新增 npm.script.ts 文件,该文件中存放 npm 执行脚本。

// src/scripts/npm.script.ts
import * as fs from "fs";
import * as path from "path";

// 获取根目录的路径
const rootPath = path.join(__dirname, "../../");
// 获取根目录的目录名
const rootDir = fs.readdirSync(rootPath);

/**
 * 获取脚本参数,处理 npm脚本 传给 node脚本 的参数,处理为一个对象
 * { env:"development" }
 * */
const scriptParams: ScriptParams = process.argv
  .filter(e => /.+=.+/g.test(e))
  .reduce((a, b) => {
    a[b.split("=")[0]] = b.split("=")[1];
    return a;
  }, {});

/**
 * 脚本方法类文件
 * 存在多个静态方法,每个静态方法都是一个脚本要执行的功能
 * */
export class RunScriptFn {
  // 创建并写入env文件,如果已经存在则删除,如果传递有env参数则创建并写入
  static createEnv(env: Env = scriptParams.env) {
    if (rootDir.includes(".env")) fs.unlinkSync(path.join(rootPath, ".env"));
    if (env) fs.writeFileSync(path.join(rootPath, ".env"), `NODE_ENV=${env}`);
  }
}

// 当执行node脚本的时候,自动执行此方法
(async function main() {
  // 通过fn参数来决定执行RunScriptFn类中的方法,不传仅执行createEnv方法
  const fns = scriptParams?.fn?.split(",") || ["createEnv"];
  // 批量执行脚本方法
  for (const fn of fns) {
    await RunScriptFn[fn]();
  }
})();

// node脚本参数
interface ScriptParams {
  // 设置的环境变量
  env?: Env;
  // 执行的Fn类下的方法,多个用英文逗号分割
  fn?: string;
}

// 环境变量
type Env = "dev" | "prod" | string;

修改 package.json

{
  // ...
  "script":{
    // 打包命令,写入环境prod
    "build": "rimraf dist && nest build && ts-node src/scripts/npm.script env=prod",
    // 开发命令,写入环境dev
    "start:dev": "ts-node src/scripts/npm.script env=dev && nest start --watch",
    // 生产环境启动命令,先打包,再使用pm2启动(如果你使用pm2启动再写)
    "start:prod": "npm run build && pm2 start dist/main.js",
  }
}

安装 @nestjs/config

npm i @nestjs/config

定义不同环境config

src/config 中定义 configuration.tsenv.dev.tsenv.prod.ts

// src/config/configuration.ts
import developmentConfig from "./env.dev";
import productionConfig from "./env.prod";

export default () => Object.assign({},{
  // 定义的环境配置,这里的键名取决于package.json中写入的环境标识
  dev: developmentConfig(),
  prod: productionConfig()
}[process.env.NODE_ENV],{
  // 额外追加的环境配置
  NEST_ENV: process.env.NODE_ENV,
});
// src/config/env.dev.ts
export default () => ({
  PORT:7200
})
// src/config/env.prod.ts
export default () => ({
  PORT:7200
})

ConfigModule 注入到 AppModule

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import configuration from "./config/configuration";

@Module({
  imports: [
    // 全局注入ConfigModule
    ConfigModule.forRoot({
      isGlobal:true,
      load:[configuration]
    })
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}

main.ts 使用

import { ConfigService } from "@nestjs/config";
// ...

(async function () {
  const app = await NestFactory.create(AppModule);

  // 配置文件
  const configService = app.get(ConfigService);
  Logger.verbose("当前环境:" + JSON.stringify(configService.get("NEST_ENV")));

  await app.listen(configService.get("PORT"), () => {
    Logger.log("-----------------------------------\n" + 
      `服务启动成功,访问地址:http://127.0.0.1:${configService.get("PORT")}` + 
      "\n-----------------------------------");
  });
})()