nestjs config
Nestjs的配置组件。
特征
- 使用Globs加载配置文件
- 支持不同的环境配置,这要归功于Dotenv
- 在运行时更改和加载配置
安装
纱
yarn add nestjs-configNPM
npm install nestjs-config --save入门
想象一下,我们的项目中有一个名为src/config的文件夹,其中包含多个配置文件。
/src
├── app.module.ts
├── config
│ ├── express.ts
│ ├── graphql.ts
│ └── grpc.ts让我们在app.module.ts中注册配置模块
import { Module } from '@nestjs/common' ;
import { ConfigModule } from 'nestjs-config' ;
import * as path from 'path' ;
@ Module ( {
imports : [
ConfigModule . load ( path . resolve ( __dirname , 'config' , '**/!(*.d).{ts,js}' ) ) ,
] ,
} )
export class AppModule { }就是这样!
复杂的项目结构
现在,假设您的应用程序不在名为src的文件夹中,而是位于src/app中。
我们希望能够设置其他“根路径”以从中加载我们的配置。无论是src还是dist 。
想象一下这样一个更复杂的项目结构:
/
├── dist/
├── src/
│ ├── app/
│ │ ├── app.module.ts
│ │ └── bootstrap/
│ │ │ ├── index.ts
│ │ │ └── bootstrap.module.ts
│ ├── migrations/
│ ├── cli/
│ ├── config/
│ │ ├── app.ts
│ │ └── database.ts
│ └── main.ts
├── tsconfig.json
└── package.json
在此示例中,配置文件位于/src/config文件夹中,因为它们在应用,迁移和CLI脚本之间共享。
同样,在打字稿汇编期间,来自src/文件夹的所有文件都将移至dist/文件夹。
此外, ConfigModule是在BootstrapModule中导入的,而不是直接在AppModule中。
// app.module.ts
import { Module } from '@nestjs/common' ;
import { BootstrapModule } from './bootstrap' ;
import { ConfigService } from 'nestjs-config' ;
ConfigService . rootPath = path . resolve ( __dirname , '..' ) ;
@ Module ( {
imports : [ BootstrapModule ] ,
} )
export class AppModule { } // bootstrap.module.ts
import * as path from 'path' ;
import { Module } from '@nestjs/common' ;
import { ConfigModule } from 'nestjs-config' ;
@ Module ( {
imports : [
ConfigModule . load ( path . resolve ( 'config' , '**/!(*.d).{ts,js}' ) ) ,
] ,
} )
export class BootstrapModule { }在调用ConfigModule.load(...)之前,请先设置ConfigService.rootPath ,将更改配置从位置加载的默认root dir。
另一种方法是从任何模块中调用ConfigModule.resolveRootPath(__dirname)然后再加载与相对路径的glob。
// bootstrap.module.ts
import { Module } from '@nestjs/common' ;
import { ConfigModule } from 'nestjs-config' ;
@ Module ( {
imports : [
ConfigModule . resolveRootPath ( __dirname ) . load ( 'config/**/!(*.d).{ts,js}' )
] ,
} )
export class BootstrapModule { }在这两种情况下,我们将配置的范围作为第一个参数提供,但相对于src/文件夹(或最终dist/ )。
多模块化配置用法
在某些情况下,您的结构可能会采用这种形状
/
├── src/
│ ├── cats/
│ │ ├── cats.module.ts
│ │ └── cats.config.ts
│ ├── dogs/
│ │ ├── dogs.module.ts
│ │ └── dogs.config.ts
│ ├── app.module.ts
│ └── main.ts
├── tsconfig.json
└── package.json
在上面的示例中,您必须调用您的配置,例如so ConfigService.get('dogs.config.bark') 。您可以使用modifyConfigName方法选项更改配置的名称
import { Module } from '@nestjs/common' ;
import { ConfigModule } from 'nestjs-config' ;
import * as path from 'path' ;
@ Module ( {
imports : [
ConfigModule . load ( path . resolve ( __dirname , '**/!(*.d).config.{ts,js}' ) , {
modifyConfigName : name => name . replace ( '.config' , '' ) ,
} ) ,
] ,
} )
export class AppModule { }现在,您可以将您的配置称为So ConfigService.get('dogs.bark') 。
生产环境
您可能已经注意到Glob中的config/**/!(*.d).{ts,js}在生产中运行(在打字稿汇编后在JavaScript中运行)时,我们想抑制打字稿定义文件。在DEV环境中使用config/**/*.ts很好,但是我们建议使用此示例config/**/!(*.d).{ts,js}以避免在生产环境中运行时以后的问题。
环境配置
该软件包带有惊人的Dotenv软件包,该软件包使您可以在首选的位置创建.env文件。
为了演示,让我们创建一个!
# .env
EXPRESS_PORT=3000现在,在我们的src/config/express.ts配置文件中,我们可以参考该环境变量。
// src/config/express.ts
export default {
port : process . env . EXPRESS_PORT || 3000 ,
}注意:默认情况下,软件包在您启动的服务器的路径中查找一个
.env文件。如果要为.env文件指定另一个路径,请使用ConfigModule.load()的第二个参数。
用法
现在,我们准备将我们想要的任何地方注入我们的ConfigService 。
import { ConfigService } from 'nestjs-config' ;
@ Injectable ( )
class SomeService {
constructor ( private readonly config : ConfigService ) {
this . config = config ;
}
isProduction ( ) {
const env = this . config . get ( 'app.environment' ) ;
return env === 'production' ;
}
}您也可以使用@InjectConfig装饰器如下:
import { InjectConfig } from 'nestjs-config' ;
@ Injectable ( )
class SomeService {
constructor ( @ InjectConfig ( ) private readonly config ) {
this . config = config ;
}
} 定制帮助者
此功能使您可以创建从配置中计算值的小型辅助函数。
从上方重新考虑isProduction()方法。但是在这种情况下,让我们将其定义为助手:
// src/config/express.ts
export default {
environment : process . env . EXPRESS_ENVIRONMENT ,
port : process . env . EXPRESS_PORT ,
// helpers
isProduction ( ) {
return this . get ( 'express.environment' ) === 'production' ;
}
}您可以使用辅助功能如下:
// this.config is the ConfigService!
this . config . get ( 'express' ) . isProduction ( ) ;
// or
this . config . _isProduction ( ) ; // note the underscore prefix. 全球助手
您还可以将帮助者附加到全球实例,如下:
this . config . registerHelper ( 'isProduction' , ( ) => {
return this . get ( 'express.environment' ) === 'production' ;
} ) ;然后这样使用:
this . config . isProduction ( ) ; // note the missing underscore prefix 装饰者
可以使用装饰器而不是注入ConfigService 。请注意, @Configurable()装饰器用自己的函数代替了该方法的descriptor.value 。关于当前的Nestjs实施(第1180期),此行为将打破@Configurable()装饰器之后的所有装饰器。
对于预期的行为, @Configurable()装饰器必须放置在一种方法的最后一个位置。
工作示例:
import { Injectable , Get } from '@nestjs/common' ;
import { Configurable , ConfigParam } from 'nestjs-config' ;
@ Injectable ( )
export default class UserController {
@ Get ( '/' )
@ Configurable ( )
index ( @ ConfigParam ( 'my.parameter' , 'default value' ) parameter ?: string ) {
return { data : parameter } ;
}
}破碎的示例:
import { Injectable , Get , UseInterceptors } from '@nestjs/common' ;
import { Configurable , ConfigParam } from 'nestjs-config' ;
import { TransformInterceptor } from '../interceptors' ;
@ Injectable ( )
export default class UserController {
@ Configurable ( )
@ Get ( '/' ) // <-- nestjs decorator won't work because it placed after @Configurable()
@ UseInterceptors ( TransformInterceptor ) // <-- nestjs decorator won't work because it placed after @Configurable()
index ( @ ConfigParam ( 'my.parameter' , 'default value' ) parameter ?: string ) {
return { data : parameter } ;
}
}破碎的示例2:
import { Injectable , Get , UseInterceptors } from '@nestjs/common' ;
import { Configurable , ConfigParam } from 'nestjs-config' ;
import { TransformInterceptor } from '../interceptors' ;
@ Injectable ( )
export default class UserController {
@ Get ( '/' ) // <-- nestjs decorator will work fine because it placed before @Configurable()
@ Configurable ( )
@ UseInterceptors ( TransformInterceptor ) // <-- nestjs decorator won't work because it placed after @Configurable()
index ( @ ConfigParam ( 'my.parameter' , 'default value' ) parameter ?: string ) {
return { data : parameter } ;
}
} typeorm
使用ConfigModule与TypeOmm结合使用(例如为了配置Typeorm),需要使用typeorm软件包为Nestjs提供的forRootAsync()函数( @nestjs/typeorm )提供
import { Module } from '@nestjs/common' ;
import { ConfigModule , ConfigService } from 'nestjs-config' ;
import { TypeOrmModule } from '@nestjs/typeorm' ;
import * as path from 'path' ;
@ Module ( {
imports : [
ConfigModule . load ( path . resolve ( __dirname , 'config' , '**' , '!(*.d).{ts,js}' ) ) ,
TypeOrmModule . forRootAsync ( {
useFactory : ( config : ConfigService ) => config . get ( 'database' ) ,
inject : [ ConfigService ] ,
} ) ,
] ,
} )
export default class AppModule { }您的配置文件可能看起来像这样:
//config/database.ts
export default {
type : 'mysql' ,
host : process . env . TYPEORM_HOST ,
username : process . env . TYPEORM_USERNAME ,
password : process . env . TYPEORM_PASSWORD ,
database : process . env . TYPEORM_DATABASE ,
port : parseInt ( process . env . TYPEORM_PORT ) ,
logging : process . env . TYPEORM_LOGGING === 'true' ,
entities : process . env . TYPEORM_ENTITIES . split ( ',' ) ,
migrationsRun : process . env . TYPEORM_MIGRATIONS_RUN === 'true' ,
synchronize : process . env . TYPEORM_SYNCHRONIZE === 'true' ,
} ;我们建议使用
TYPEORM_前缀,以便在生产环境中运行时,您还可以使用相同的ENV来运行Typeorm CLI。这里有更多选项
自定义env文件路径
您可以使用加载方法的第二个参数指定dotenv选项
ConfigModule . load ( path . resolve ( __dirname , '*/**!(*.d).config.{ts,js}' ) , {
path : path . resolve ( __dirname , '..' , '.env.staging' ) ) ,
} ) ; 使用不同的env文件
在您的应用程序的根目录中创建.env文件一直是最佳实践。您也可以每个不同的环境创建自定义.ENV文件。
# .env
EXPRESS_PORT=3000
# .env.dev
EXPRESS_PORT=3001
# .env.testing
EXPRESS_PORT=3002
# .env.staging
EXPRESS_PORT=3003 const ENV = process . env . NODE_ENV ;
ConfigModule . load ( path . resolve ( __dirname , '*/**!(*.d).config.{ts,js}' ) , {
path : path . resolve ( process . cwd ( ) , ! ENV ? '.env' : `.env. ${ ENV } ` ) ,
} ) ;也许您需要一个自定义目录来管理Env文件。
在此示例中,自定义目录的名称为env 。
/
├── dist/
├── env/
│ ├── .env.dev
│ ├── .env.testing
│ └── .env.staging
│ │
├── src/
│ ├── config/
│ │ └── typeorm.config.ts
│ └── main.ts
├── tsconfig.json
└── package.json const ENV = process . env . NODE_ENV ;
ConfigModule . load ( path . resolve ( __dirname , '*/**!(*.d).config.{ts,js}' ) , {
path : path . resolve ( process . cwd ( ) , 'env' , ! ENV ? '.env' : `.env. ${ ENV } ` ) ,
} ) ;注意:如果将ENV文件放置在
src目录中,则将无法将ENV文件视为outDir中的最终输出,因为TS编译器将永远不会将与 *.TS扩展不匹配的传输文件。
支持
欢迎任何支持。至少你可以给我们一个明星
贡献者
代码贡献者
由于所有贡献的人,该项目的存在。 [贡献]。
ConfigService API
get(param:string | string [],value:any = undefined):
通过路径获取配置值,您可以使用dot notation来遍历嵌套对象。如果键不存在,它将返回默认值。
this . config . get ( 'server.port' ) ; // 3000
this . config . get ( 'an.undefined.value' , 'foobar' ) ; // 'foobar' is returned if the key does not exist set(param:string | string [],值:any = null):config
在运行时设置一个值,如果不存在,它会创建指定的键 /值。
this . config . set ( 'server.port' , 2000 ) ; // {server:{ port: 2000 }} has(param:string | string []):布尔值
确定配置的给定路径是否存在并设置。
this . config . has ( 'server.port' ) ; // true or false 合并(环球:字符串,选项?:dotenvoptions):承诺
在运行时加载其他配置文件。这非常适合包装开发。
@ Module ( { } )
export class PackageModule implements NestModule {
constructor ( @ InjectConfig ( ) private readonly config ) { }
async configure ( consumer : MiddlewareConsumer ) {
await this . config . merge ( path . resolve ( __dirname , '**/!(*.d).{ts,js}' ) ) ;
}
} registerHelper(名称:字符串,fn:(... args:any [])=> any):configService
注册自定义全局助手功能
this . config . registerHelper ( 'isProduction' , ( ) => {
return this . get ( 'express.environment' ) === 'production' ;
} ) ; ResolverootPath(路径:字符串):typeof ConfigService
从加载配置文件的位置更改根路径
import { Module } from '@nestjs/common' ;
import { ConfigModule } from 'nestjs-config' ;
@ Module ( {
imports : [
ConfigModule . resolveRootPath ( __dirname ) . load ( path . resolve ( __dirname , '**/!(*.d).{ts,js}' ) ) ,
] ,
} )
export class AppModule { } root(路径:string =''):字符串
返回当前工作的DIR或定义的rootpath。
ConfigService . root ( ) ; // /var/www/src
ConfigService . root ( 'some/path/file.html' ) ; // /var/www/src/some/path/file.html
ConfigService . resolveRootPath ( __dirname ) . root ( ) ; // /var/www/src/app (or wherever resolveRootPath has been called with)通过命令行克隆项目: