配置
配置问题:
- 直接使用
.env
文件,则会出现大量的process.env.xx
的写法,且只能单独一个个获取,无法直接获取对象。
配置方案:
- 使用
useClass
环境变量的配置在
.env
里面配置后,需要引入到config/envs
内部的不同文件中再做一次配置,最后使用configSerivce
注入来获取配置信息
- 可以将环境变量验证和转换为深层对象模式
config.module.ts
{
provide: 'ConfigServiceUseClass',
useClass:
process.env.NODE_ENV === 'development'
? DevelopmentConfigService
: ProductionConfigService,
},
DevelopmentConfigService(ProductionConfigService类同)
import { Injectable } from '@nestjs/common';
@Injectable()
export class DevelopmentConfigService {
getConfig() {
return 'development'; // 伪代码,这里应该返回环境变量转换的深层对象。
}
}
控制器中使用
@Inject('ConfigServiceUseClass')
private ConfigServiceUseClass:
| DevelopmentConfigService
| ProductionConfigService,
@Get()
getConfig() {
return this.ConfigServiceUseClass.getConfig();
}
- 动态模块方式。
- 使用
dotenv
来做引入解析。 - 动态配置
- 可以配置
development.env
等.env
文件 - 变量默认是单值,获取不方便
- 可以在引入环境变量后,将环境变量验证和转换为深层对象模式
config.module.ts
// 动态模块
export class ConfigModule {
static register(options: OptionsInterface): DynamicModule {
return {
module: ConfigModule,
providers: [
{
provide: CONFIG_OPTIONS,
useValue: options,
},
ConfigService,
],
exports: [ConfigService],
};
}
}
contant.ts
export const CONFIG_OPTIONS = 'CONFIG_OPTIONS';
export const DATA_SOURCE = 'DATA_SOURCE';
export const PHOTO_REPOSITORY = 'PHOTO_REPOSITORY';
app.module.ts
// 注入配置
ConfigModule.register({ folder: './envs' }),
config.service.ts
import { Injectable, Inject } from '@nestjs/common';
import { EnvConfig } from './interfaces';
import * as fs from 'fs';
import * as dotenv from 'dotenv';
import { resolve } from 'path';
import { CONFIG_OPTIONS } from '../constants';
import { OptionsInterface } from './interfaces';
@Injectable()
export class ConfigService {
private readonly evnConfig: EnvConfig;
constructor(@Inject(CONFIG_OPTIONS) private options: OptionsInterface) {
const filePath = `${process.env.NODE_ENV || 'development'}.env`;
// const envFile = resolve(__dirname, '../../', this.options.folder, filePath); // 普通模块路径
// const envFile = resolve(__dirname, '../', this.options.folder, filePath); // webpack模式路径
// const envFile = resolve(process.cwd(), this.options.folder, filePath); // webpack
const envFile = resolve(this.options.folder, filePath); // webpack
this.evnConfig = dotenv.parse(fs.readFileSync(envFile));
// 重组envConfig为深层对象模式。
}
get(key: string): string {
console.log('this.evnConfig', this.evnConfig);
return this.evnConfig[key];
}
}
envs/development.env
envs/production.env
NODE_ENV=development
...
控制器中使用
private configService: ConfigService,
@Get()
getEnvConfig(@Query('key') key: string) {
return this.configService.get(key);
}
- 使用自带的
@nestjs/config
,设置一个.env
文件,在config/envs
内分别设置不同环境的js
文件来做验证和配置。然后在configuration.ts中进行环境配置项的合并。(目前使用的方法)
- 不需要写其他服务方法,最便捷。
安装nestjs
自带的配置模块
npm i @nestjs/config
引入环境变量并转换为深层对象模式
envs/
default.ts
develoment.ts
production.ts
import { env } from 'process';
export const config = {
db: {
type: env.DB_TYPE || 'mysql',
host: env.DB_HOTST || 'localhost',
port: env.DB_PORT || 3306,
username: env.DB_USER || '',
passwrod: env.DB_PASSWROD || '',
database: env.DB_NAME || '',
logging: false,
synchronize: false,
autoLoadEntities: true,
},
service: {
port: env.PORT || 7000,
portDoc: env.PORTDOC || 9000,
},
};
configuration.ts
import { mergeAll } from 'ramda';
import type { Config, Production, Default } from './configuration.interface';
export const configuration = async (): Promise<Config> => {
const { config } = <{ config: Default }>(
await import(`${__dirname}/envs/default`)
);
const { config: environment } = <{ config: Production }>(
await import(`${__dirname}/envs/${process.env.NODE_ENV || 'development'}`)
);
return mergeAll([config, environment]);
};
configuration.interface.ts
import type { config as base } from './envs/default';
import type { config as production } from './envs/production';
export type Default = typeof base;
export type Production = typeof production;
export type Config = Default & Production;
export type ObjectType = Record<string, unknown>;
app.module.ts
ConfigModule.forRoot({
isGlobal: true,
load: [configuration], // 直接加载
expandVariables: true, // 扩展变量,使用变量比如: API_URL=locahost:${PORT}
}),
优化点:
- 可以使用
joi
包来对环境变量做校验。
增减环境配置
env
增减- 各个环境配置文件增减
- 接口文件增减
- 作校验
目前的操作思路比较清晰。