nestjs config
Nestjs的配置组件。
特征
- 使用Globs加载配置文件
- 支持不同的环境配置,这要归功于Dotenv
- 在运行时更改和加载配置
安装
纱
yarn add nestjs-config
NPM
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)
