经验分享
Nestjs的环境变量解决方案
方案一:自定义执行脚本 实现思路 nestjs 本身是可以读取到根目录的 .env 文件的,以此为突破口,在 .env 文件中添加环境变量 NODE_ENV=development当我们执行 npm
2023-07-01 20:10:35
19

方案一:自定义执行脚本

实现思路

  1. nestjs 本身是可以读取到根目录的 .env 文件的,以此为突破口,在 .env 文件中添加环境变量 NODE_ENV=development
  2. 当我们执行 npm run start:dev 时,给 .env 文件中写入 NODE_ENV=development
  3. 当我们执行 npm run build 时,给 .env 文件中写入 NODE_ENV=production
  4. 通过编写一个 node 脚本文件,当执行 npm脚本 的时候也顺便执行这个 node脚本 并传参,在 node脚本 文件中操作 .env 文件

新建node脚本

src 下新建 script/NpmScript.ts 文件

/**
 * 执行npm run 执行的脚本
 * */

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 = "development" | "production";

执行node脚本

通过改写 package.json 中的 script 属性来执行 node脚本
这里以 buildstart:dev 为例

"scripts": {
    // build的时候应该是先打包,再写入.env文件
    "build": "nest build && ts-node src/script/NpmScript env=production",
    // start:dev 的时候应该是先写入.env,再执行nest start
    "start:dev": "ts-node src/script/NpmScript env=development && nest start --watch",
  },

node脚本 的参数详见 ScriptParams
例:

ts-node src/script/NpmScript env=production fn=createEnv,xxx,ooo