[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等类型的文件格式
相关推荐
kongxx10 天前
NestJS中使用Guard实现路由保护
nestjs
白雾茫茫丶11 天前
Nest.js 实战 (十二):优雅地使用事件发布/订阅模块 Event Emitter
nestjs·nest.js·发布订阅·event emitter
lph65821 个月前
比起上传资源更应该懂得如何资源回收
node.js·nestjs
gsls2008081 个月前
将nestjs项目迁移到阿里云函数
阿里云·云计算·nestjs·云函数
d3126975101 个月前
在Nestjs使用mysql和typeorm
mysql·express·nestjs·typeorm
剪刀石头布啊2 个月前
nestjs-版本控制
nestjs
潇洒哥gg2 个月前
重生之我在NestJS中使用jwt鉴权
前端·javascript·nestjs
huangkaihao2 个月前
【NestJS学习笔记】 之 自定义装饰器
前端·node.js·nestjs
鹿鹿鹿鹿isNotDefined2 个月前
Nest 源码解析:依赖注入是怎么实现的?
nestjs
剪刀石头布啊2 个月前
nestjs-自定义装饰器
nestjs