fontcolor_theme
Deepkit App

配置

在 Deepkit 应用中,模块和你的应用本身都可以拥有配置选项。 例如,配置可以包含数据库 URL、密码、IP 等。服务、HTTP/RPC/CLI 控制器以及模板函数可以通过依赖注入读取这些配置选项。

可以通过定义带有属性的类来定义配置。这是一种为整个应用定义配置的类型安全方式,其值会自动序列化并验证。

示例

import { MinLength } from '@deepkit/type';
import { App } from '@deepkit/app';

class Config {
    pageTitle: string & MinLength<2> = 'Cool site';
    domain: string = 'example.com';
    debug: boolean = false;
}

const app = new App({
    config: Config
});


app.command('print-config', (config: Config) => {
    console.log('config', config);
})

app.run();
$ curl http://localhost:8080/
Hello from Cool site via example.com

当未使用任何配置加载器时,将使用默认值。要更改配置,你可以使用 app.configure({domain: 'localhost'}) 方法,或使用环境配置加载器。

设置配置值

默认情况下,不会覆盖任何值,因此会使用默认值。设置配置值有多种方式。

  • 通过 app.configure({})
  • 为每个选项使用环境变量
  • 通过 JSON 的环境变量
  • dotenv 文件

你可以同时使用多种方法来加载配置。它们被调用的顺序很重要。

环境变量

要允许通过各自的环境变量设置每个配置选项,请使用 loadConfigFromEnv。默认前缀为 APP_,你可以更改它。它还会自动加载 .env 文件。默认使用大写命名策略,你也可以更改。

对于像上面的 pageTitle 这样的配置选项,你可以使用 APP_PAGE_TITLE="Other Title" 来更改其值。

new App({
    config: config,
    controllers: [MyWebsite],
})
    .loadConfigFromEnv({prefix: 'APP_'})
    .run();
APP_PAGE_TITLE="Other title" ts-node app.ts server:start

JSON 环境变量

要通过单个环境变量更改多个配置选项,请使用 loadConfigFromEnvVariable。第一个参数是环境变量的名称。

new App({
    config: config,
    controllers: [MyWebsite],
})
    .loadConfigFromEnvVariable('APP_CONFIG')
    .run();
APP_CONFIG='{"pageTitle": "Other title"}' ts-node app.ts server:start

DotEnv 文件

要通过 dotenv 文件更改多个配置选项,请使用 loadConfigFromEnv。第一个参数可以是一个 dotenv 文件的路径(相对于 cwd),也可以是多个路径。如果是数组,将按顺序尝试每个路径,直到找到存在的文件为止。

new App({
    config: config,
    controllers: [MyWebsite],
})
    .loadConfigFromEnv({envFilePath: ['production.dotenv', 'dotenv']})
    .run();
$ cat dotenv
APP_PAGE_TITLE=Other title
$ ts-node app.ts server:start

模块配置

每个被导入的模块都可以有一个模块名。该名称用于上面提到的配置路径。

例如,对于环境变量配置,FrameworkModule 的端口选项对应的路径是 FRAMEWORK_PORT。默认情况下,所有名称都写成大写。如果使用了 APP_ 前缀,则可以通过如下方式更改端口:

$ APP_FRAMEWORK_PORT=9999 ts-node app.ts server:start
2021-06-12T18:59:26.363Z [LOG] Start HTTP server, using 1 workers.
2021-06-12T18:59:26.365Z [LOG] HTTP MyWebsite
2021-06-12T18:59:26.366Z [LOG]     GET / helloWorld
2021-06-12T18:59:26.366Z [LOG] HTTP listening at http://localhost:9999/

在 dotenv 文件中也同样写作 APP_FRAMEWORK_PORT=9999

而在通过 loadConfigFromEnvVariable('APP_CONFIG') 的 JSON 环境变量中,使用的是实际配置类的结构。framework 变成一个对象。

$ APP_CONFIG='{"framework": {"port": 9999}}' ts-node app.ts server:start

这对所有模块都同样适用。对于你的应用自身的配置选项(new App)不需要模块前缀。

配置类

import { MinLength } from '@deepkit/type';

export class Config {
    title!: string & MinLength<2>; //这使其成为必填项,必须提供
    host?: string;

    debug: boolean = false; //也支持默认值
}
import { createModuleClass } from '@deepkit/app';
import { Config } from './module.config.ts';

export class MyModule extends createModuleClass({
  config: Config
}) {
}

配置选项的值可以在模块的构造函数中提供,使用 .configure() 方法提供,或通过配置加载器提供(例如环境变量加载器)。

import { MyModule } from './module.ts';

new App({
   imports: [new MyModule({title: 'Hello World'})],
}).run();

要动态更改已导入模块的配置选项,可以使用 process 钩子。这是一个很好的位置,用于重定向配置选项,或根据当前模块配置或其他模块实例信息来设置已导入模块。

import { MyModule } from './module.ts';

export class MainModule extends createModuleClass({
}) {
    process() {
        this.getImportedModuleByClass(MyModule).configure({title: 'Changed'});
    }
}

在应用层级,这稍有不同:

new App({
    imports: [new MyModule({title: 'Hello World'}],
})
    .setup((module, config) => {
        module.getImportedModuleByClass(MyModule).configure({title: 'Changed'});
    })
    .run();

当根应用模块由常规模块创建时,其工作方式与常规模块类似。

class AppModule extends createModuleClass({
}) {
    process() {
        this.getImportedModuleByClass(MyModule).configure({title: 'Changed'});
    }
}

App.fromModule(new AppModule()).run();

读取配置值

在服务中使用配置选项时,你可以使用常规的依赖注入。可以注入整个配置对象、单个值或配置的一部分。

部分

若只注入配置值的子集,请使用 Pick 类型。

import { Config } from './module.config';

export class MyService {
     constructor(private config: Pick<Config, 'title' | 'host'}) {
     }

     getTitle() {
         return this.config.title;
     }
}


//在单元测试中,可以通过以下方式实例化
new MyService({title: 'Hello', host: '0.0.0.0'});

//或者你可以使用类型别名
type MyServiceConfig = Pick<Config, 'title' | 'host'};
export class MyService {
     constructor(private config: MyServiceConfig) {
     }
}

单个值

若只注入单个值,请使用索引访问操作符。

import { Config } from './module.config';

export class MyService {
     constructor(private title: Config['title']) {
     }

     getTitle() {
         return this.title;
     }
}

全部

若要注入所有配置值,请使用该类作为依赖。

import { Config } from './module.config';

export class MyService {
     constructor(private config: Config) {
     }

     getTitle() {
         return this.config.title;
     }
}
English中文 (Chinese)한국어 (Korean)日本語 (Japanese)Deutsch (German)