nestjs config

Delphi源码 2025-08-12

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)

下载源码

通过命令行克隆项目:

git clone https://github.com/nestjsx/nestjs-config.git