[Nest.js]-多环境配置管理

前言

通常开发环境会包含环境:开发(development)、测试(test)和生产(production)。而每个环境可能需要不同的配置,像数据库连接,密钥等。这些敏感信息不会硬编码在代码里,把这些敏感信息在环境变量中设置,从而提高安全性。随着项目的增长,配置项可能会增加。通过环境配置文件管理,也可以更容易的管理和更新这些配置,所以多环境配置是必要的。

多环境配置常用的两种方案

创建项目

bash 复制代码
mkdir config-test 
cd ./config-test
pnpm init
  • 安装cross-env
bash 复制代码
pnpm i cross-env

它可以设置修改跨平台的环境变量,因为在Windows、macOS、Linux 系统在设置环境变量时有不同的方式

  • 在package.json脚本中设置运行命令
json 复制代码
...
"scripts": {
  "dev": "cross-env NODE_ENV=development node index.js",
  "prod": "cross-env NODE_ENV=production node index.js"
}
...

dotenv

dotenvdotenv - npm (npmjs.com) 是以键值对形式来去配置,它会默认加载 .env 文件中的环境变量到 process.env

安装dotenv

bash 复制代码
pnpm i dotenv

在根目录创建.env配置文件

ini 复制代码
DB_HOST = localhost
DB_PORT = 3306

在index.js里引入并加载

可以看到打印的信息有包含了.env配置文件里的环境变量,如果是多环境呢? 我们在根目录创建.development.env并添加以下配置

.development.env 复制代码
DB_HOST = localhost-dev
DB_PORT = 3306

调整index.js文件中dotenv=>config配置对象
path:可选默认情况下查找.env文件,也可以指定读取的.env文件,也可以传递一个数组指定多个文件路径,如果在多个文件中设置了同一个变量,由左至右,第一个优先级最高

js 复制代码
const dotenv = require('dotenv');
const envpath = [`.${process.env.NODE_ENV || 'development'}.env`, '.env'];
'.env',
  dotenv.config({
    path: envpath,
  });
console.log('DB=>', process.env.DB_HOST, process.env.DB_PORT);

可以看到在.development.env中配置的环境变量就被打印出来,并覆盖了.env文件里的配置

配置文件通常存放在项目根目录下的 /config 目录中 主配置文件(默认配置)通常命名为 default.json

需要创建特定的配置文件 如 development.json, test.json, production.json 等。这些配置将覆盖默认配置中的值。

config

configconfig - npm (npmjs.com) 它允许创建多个配置文件,可以根据不同环境加载相应的配置,并对默认(公共)配置覆盖合并

安装config

bash 复制代码
pnpm i config

json配置文件

在项目根目录中创建config文件夹,新增default.json,production.json 分别添加以下配置信息

json 复制代码
// default.json
{
  "DB": {
    "USER": "root",
    "PASSWORD": "root",
    "HOST": "localhost",
    "PORT": 3306
  }
}
// production.json
{
  "DB": {
    "USER": "root",
    "PASSWORD": "root",
    "HOST": "localhost-prod"
  }
}

在index.js中导入config,并打印config中的配置

js 复制代码
const config = require('config');
console.log('DB=>', config.get('DB'));

可以看到default.json和production.json自动做了合并处理

yaml配置文件

config不能直接读取yaml格式文件需要安装js-yaml 这个包,再将config文件夹下json文件改写成yml格式

yml 复制代码
## default.yml
DB:
  USER: "oot"
  PASSWORD: "root"
  HOST: "localhost"
  PORT: 3306
  TYPE: "yaml"
## production.yml
DB:
  USER: "root"
  PASSWORD: "root"
  HOST: "localhost-prod"

执行pnpm run prod

在nestjs项目环境中配置

使用Nest CLI创建项目,如果没有安装的,全局安装下@nestjs/cli(先检查node版本是否(>= 12, v13 版本除外))

bash 复制代码
nest new config-demo-nestjs -p pnpm

同样的,安装cross-env,在package.json配置运行脚本

json 复制代码
"scripts": {
    "start:dev": "cross-env NODE_ENV=development nest start --watch",
    "start:prod": "cross-env NODE_ENV=production node dist/main",
  },

官方方案使用 @nestjs/config来配置

安装配置依赖包@nestjs/config

内部使用 dotenv 实现

bash 复制代码
pnpm install @nestjs/config      

在根目录添加.env, .development.env文件

js 复制代码
// .env
DB_HOST = localhost
DB_PORT = 3306
// .development.env
DB_HOST = localhost-dev
DB_USERNAME = root
DB_PASSWORD = example
DB_PORT = 3306

通常来讲这些配置信息需要全局进行配置,我们在AppModule中导入使用,ConfigModule中的forRoot方法(不做任何配置默认读取.env文件)

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

@Module({
  imports: [ConfigModule.forRoot()],
  ...
})

AppController中注入依赖

ts 复制代码
private configService: ConfigService

pnpm start:dev启动项目,访问3000端口,DB_HOST的值被打印出来了 指定一个或多个文件路径也是可以的,通过ForRoot配置对象里的envFilePath属性来设置

ts 复制代码
const envFilePath = [`.${process.env.NODE_ENV || 'development'}.env`, '.env'];

重新启动项目访问3000端口 分别输出了DB_HOST,DB_USERNAME,DB_HOST的值 这里也是前面的配置会覆盖后面的配置

官方方案 进阶用法

.env里配置满足大多数情况下使用的场景,配置层级简单,如果配置项是层级嵌套的,需要灵活去配置(yaml,json或其他类型的文件)。键值对的形式就不太适用了

在forRoot配置里可以加载自定义配置文件,通过load属性来设置,数组中的每一项是一个函数,支持异步方法,函数的返回值就是配置项

安装js-yaml这个包用于解析yaml格式文件

bash 复制代码
pnpm install js-yaml

在根目录创建config,并添加yaml文件(同上述中的yaml配置文件,在这里不需要去指定某个文件名)

在src下创建configuration.ts

  1. process.env.NODE_ENV获取当前的环境
  2. path.join获取对应的文件路径
  3. fs.readFileSync读取文件中的内容
  4. yaml.load将 YAML 字符转换为 JavaScript 对象
  5. 安装lodash,使用merge方法两个配置文件数据合并
ts 复制代码
import * as fs from 'fs';
import * as path from 'path';
import * as yaml from 'js-yaml';
import * as _ from 'lodash';
const basisfilename = 'default.yml';
const envpathfileName = `${process.env.NODE_ENV || 'development'}.yml`;


function readYamlFile(fileName) {
   // 获取文件路径 
  const filePath = path.join(__dirname, '../config', fileName);
  const file = fs.readFileSync(filePath, 'utf8');
  const data = yaml.load(file);
  return data;
}

export default () => {
    // 通过lodash中的merge方法合并
  return _.merge(readYamlFile(basisfilename), readYamlFile(envpathfileName));
};

在AppController中引入

ts 复制代码
import configuration from './configuration';

在AppController中打印输入

load里和envFilePath的配置加载优先级是相反的:后面的覆盖前面的

可以在load里添加一些相同参数的数据试下

js 复制代码
() => ({
  DB: {
    USER: 'root-test',
    PASSWORD: 'root',
    HOST: 'localhost-dev',
    PORT: 3306,
    TYPE: 'yaml',
  },
}),

可以看到 第一项数据的值DB=>USER就被覆盖掉了

使用第三方包 config来配置

多环境配置总结

  1. 使用环境变量来区分不同环境,常用的是process.env.NODE_ENV,针对不同环境创建不同的配置文件
  2. 配合一些库例如dotenvconfig帮助我们加载和合并特定环境的配置
  3. 像一些简单的配置可以使用.env键值对形式配置,对于有层级嵌套关系的可以考虑yaml,json等类型的文件格式
相关推荐
Eric_见嘉2 天前
NestJS 🧑‍🍳 厨子必修课(九):API 文档 Swagger
前端·后端·nestjs
XiaoYu200210 天前
第3章 Nest.js拦截器
前端·ai编程·nestjs
XiaoYu200212 天前
第2章 Nest.js入门
前端·ai编程·nestjs
实习生小黄12 天前
NestJS 调试方案
后端·nestjs
当时只道寻常16 天前
NestJS 如何配置环境变量
nestjs
濮水大叔1 个月前
VonaJS是如何做到文件级别精确HMR(热更新)的?
typescript·node.js·nestjs
ovensi1 个月前
告别笨重的 ELK,拥抱轻量级 PLG:NestJS 日志监控实战指南
nestjs
ovensi1 个月前
Docker+NestJS+ELK:从零搭建全链路日志监控系统
后端·nestjs
Gogo8161 个月前
nestjs 的项目启动
nestjs