Skip to content

配置项

配置项

  • 就是把那些数据库配置、端口配置、日志配置、缓存配置、文件上传配置、邮件配置、第三方配置等,这些配置项,统一放到一个文件中,方便管理。

两种方式 1.env 文件 2. yml 配置

安装

bash

pnpm i @nestjs/config -S
pnpm i cross-env -S
pnpm i dotenv -S

根目录

在根目录,不在 src 目录下

  • 创建.env文件
bash
DATABASE_USER=root
DATABASE_PASSWORD=123456
DATABASE_NAME=testnest1
DATABASE_HOST=localhost
DATABASE_PORT=3306
DATA="EVN或者PRO没用的配置"
  • 创建.env.development
bash

DATABASE_USER=root
DATABASE_PASSWORD=123456
DATABASE_NAME=testnest1
DATABASE_HOST=localhost
DATABASE_PORT=3306
DATA="测试服"
  • 创建.env.production
bash

DATABASE_USER=root
DATABASE_PASSWORD=123456
DATABASE_NAME=testnest1
DATABASE_HOST=localhost
DATABASE_PORT=3306
DATA="正式服"

找到 package.json 文件

bash
"start:dev": "cross-env NODE_ENV=development nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "cross-env NODE_ENV=production node dist/main",

基础版

  • 找到根目录 app.module.ts 模块
ts
import { Module } from "@nestjs/common";
import { LoginModule } from "./Login/login.module";
import { UserModule } from "./User/user.module";

// 配置文件
import { ConfigModule } from "@nestjs/config";
import * as dotenv from "dotenv";
const envPath = `.env.${process.env.NODE_ENV || "development"}`;

@Module({
  imports: [
    UserModule,
    LoginModule,
    // 修改配置
    ConfigModule.forRoot({
      isGlobal: true,
      envFilePath: envPath,
      // 这里新增.env的文件解析
      load: [() => dotenv.config({ path: ".env" })],
    }),
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}
  • 使用
ts
import { Inject, Injectable } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
@Injectable()
export class LoginService {
  constructor() {}
  @Inject()
  private ConfigService: ConfigService;

  async login(): Promise<string> {
    return this.ConfigService.get("DATABASE_USER");
  }
}

高级版本

测试用例

ts
import { TypeOrmCrudService } from "@nestjsx/crud-typeorm";
import { Inject, Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import UserEntity from "../model/User.entity";
import { ConfigService } from "@nestjs/config";
@Injectable()
export class UserService extends TypeOrmCrudService<UserEntity> {
  constructor(@InjectRepository(UserEntity) repo) {
    super(repo);
  }
  @Inject()
  private ConfigService: ConfigService;

  async createUser(username: string) {
    console.log(this.ConfigService.get("DATABASE_NAME"));
    // const user = new UserEntity();
    // user.username = username;
    // return await this.repo.save(user);
  }
}

修改数据库配置

  • src 目录下面新建一个 config 文件夹里面 新建一个 orm.config.ts
ts
import { TypeOrmModuleOptions } from "@nestjs/typeorm";
import * as fs from "fs";
import * as dotenv from "dotenv";
import * as path from "path";
// 匹配所有实体
const entitiesDir = [path.join(__dirname, "../**/*.entity{.ts,.js}")];

// 通过环境变量读取不同的.env文件
function getEnv(env: string): Record<string, string> {
  if (fs.existsSync(env)) {
    return dotenv.parse(fs.readFileSync(env));
  }
  return {};
}
// 通过dotENV来解析不同的配置
function buildConnectionOptions() {
  const defaultConfig = getEnv(".env");
  const envConfig = getEnv(`.env.${process.env.NODE_ENV || "development"}`);
  const config = {
    ...defaultConfig,
    ...envConfig,
  };
  return {
    type: "mysql",
    host: config.DATABASE_HOST,
    port: config.DATABASE_PORT,
    username: config.DATABASE_USER,
    password: config.DATABASE_PASSWORD,
    database: config.DATABASE_NAME,
    entities: entitiesDir,
    synchronize: false, //同步本地的schema与数据库 ->初始化的时候使用
    logging: ["error"], //日志等级
  };
}

export const connectionOptions =
  buildConnectionOptions() as TypeOrmModuleOptions;

找到连接数据库的模块文件

xxxx.module.ts

ts
import { Global, Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import User from "./model/User.entity";
import { UserController } from "./controller/user.controller";
import { UserService } from "./service/user.service";
import { ConfigModule } from "@nestjs/config";
import * as dotenv from "dotenv";
// 修改数据库配置
import { connectionOptions } from "../config/orm.config";
const envPath = `.env.${process.env.NODE_ENV || "development"}`;
@Global()
@Module({
  imports: [
    TypeOrmModule.forRoot(connectionOptions),
    TypeOrmModule.forFeature([User]),
    // 修改配置
    ConfigModule.forRoot({
      isGlobal: true,
      envFilePath: envPath,
      // 这里新增.env的文件解析
      load: [() => dotenv.config({ path: ".env" })],
    }),
  ],
  controllers: [UserController],
  providers: [UserService],
})
export class CoreModule {}

使用 yaml 方式配置

安装依赖

安装 js-yaml 包和类型

ts
npm i js-yaml -S

npm i @types/js-yaml -D

pnpm i @nestjs/config -S

pnpm i cross-env -S

src 文件夹下创建一个 config 目录来放各个环境的配置,这里创建 3 个环境 dev/prod/test

ts
── src
│   ├── app.module.ts
│   ├── config
│   │   ├── dev.yml
│   │   ├── index.ts
│   │   ├── prod.yml
│   │   └── test.yml
│   ├── main.ts
│   └── user
│       ├── dto
│       │   ├── create-user.dto.ts
│       │   └── update-user.dto.ts
│       ├── entities
│       │   └── user.entity.ts
│       ├── user.controller.ts
│       ├── user.module.ts
│       └── user.service.ts
├── tsconfig.build.json
└── tsconfig.json

config/index.ts是动态加载所有配置的入口页,代码如下

ts
import { readFileSync } from "fs";
import * as yaml from "js-yaml";
import { join } from "path";
const configFileNameObj = {
  development: "dev",
  test: "test",
  production: "prod",
};
const env = process.env.NODE_ENV;
export default () => {
  return yaml.load(
    readFileSync(join(__dirname, `./${configFileNameObj[env]}.yml`), "utf8")
  ) as Record<string, any>;
};

这里有个需要注意的地方导入 js-yaml 的时候一定要用\* as yaml 或者 require()

不然的话会报错 load 方法不存在,当然你也可以单独导入方法,看你喜好。

还需要注意的是导出必须是个函数,以为配置包的 load 方法只接受函数数组

yml格式的配置文件比如dev.yml

ts
# 数据库配置
db:
  host: localhost
  port: 3306
  user: root
  password: root
  database: blog

# Redis配置
redis:
  host: localhost
  port: 6379
  password: root

# JWT配置
jwt:
  secret: secret
  expiration: 3600

# 普通配置

base:
  url: http://localhost:8080
  data: devdata

然后在 app.module.ts 中配置导入 yml 配置

ts
import configuration from './config/index';

@Module({
  imports: [
    ConfigModule.forRoot({
      cache: true,
      load: [configuration],
      isGlobal: true,
    }),
  ],
  controllers: [],
  providers: [],
})

现在如果启动项目的话,大概率 yml 文件会找不到而报错,此时还需要去配置下 cli 的配置文件 nest-cli.json

ts
{
  "$schema": "https://json.schemastore.org/nest-cli",
  "collection": "@nestjs/schematics",
  "sourceRoot": "src",
  "compilerOptions": {
    "assets": ["**/*.yml"],
    "deleteOutDir": true,
    "watchAssets": true
  },
  "generateOptions": {
    "spec": false
  }
}

特别注意的就是这个打包配置 compilerOptions 中的 assets,这个要配置成所有的 yml 文件,这样才能在 dist 中找到配置的配置文件

ts
dist
│   ├── app.module.d.ts
│   ├── app.module.js
│   ├── app.module.js.map
│   ├── config
│   │   ├── dev.yml
│   │   ├── index.d.ts
│   │   ├── index.js
│   │   ├── index.js.map
│   │   ├── prod.yml
│   │   └── test.yml

接下来还需要去修改一下 npmscript 命令,加上环境变量来运行对应的环境配置,先安装一个 cross-env

ts
npm i cross-env -D

然后修改对应环境的脚本命令

ts
 "start:dev": "cross-env NODE_ENV=development nest start --watch",
 "start:debug": "cross-env NODE_ENV=development nest start --debug --watch",
 "start:test": "cross-env NODE_ENV=test node dist/main",
 "start:prod": "cross-env NODE_ENV=production node dist/main",

使用配置

使用配置的话,需要导入@nestjs/config 提供的服务来获取配置信息,比如在 user 模块使用配置

因为配置已经设置为全局可用,所以不再需要在 user 模块中导入了,可以直接使用

ts
import { ConfigService } from '@nestjs/config';

@Controller('user')
export class UserController {
  constructor(
    private readonly userService: UserService,
    private configService: ConfigService,
  ) {}

  @Get()
  findAll() {
    console.log('configService===', this.configService.get('db'));

    return this.userService.findAll();
  }

这里能打印出对应的配置说明多配置环境可以使用了,这是在控制器里面使用这个配置服务,通过注入的方式

那如果是想在模块文件中使用配置服务怎么办,就拿数据库的配置来举例

ts
@Module({
  imports: [
    // 数据库
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => {
        return {
          type: 'mysql',
          // 可能不再支持这种方式,entities 将改成接收 实体类的引用
          //
          // entities: [`${__dirname}/**/*.entity{.ts,.js}`],
          autoLoadEntities: true,
          keepConnectionAlive: true,
          ...config.get('db.mysql'),
          // cache: {
          //   type: 'ioredis',
          //   ...config.get('redis'),
          //   alwaysEnabled: true,
          //   duration: 3 * 1000, // 缓存3s
          // },
        } as TypeOrmModuleOptions;
      },
    }),
  ],
  controllers: [],
  providers: [],
})

由配置的例子可以看出通过一个 useFactory 函数,然后将配置服务作为参数传递进行使用,就可以在模块文件中使用配置信息了

根据现有的数据库自动生成实体

安装

ts

pnpm i typeorm-model-generator

相关参数说明

ts
Usage: typeorm-model-generator -h <host> -d <database> -p [port] -u <user> -x
[password] -e [engine]

Options:
  --help                 Show help                                     [boolean]
  --version              Show version number                           [boolean]
  -h, --host             IP address/Hostname for database server
                                                          [default: "127.0.0.1"]
  -d, --database         Database name(or path for sqlite)            [required]
  -u, --user             Username for database server
  -x, --pass             Password for database server              [default: ""]
  -p, --port             Port number for database server
  -e, --engine           Database engine
          [choices: "mssql", "postgres", "mysql", "mariadb", "oracle", "sqlite"]
                                                              [default: "mssql"]
  -o, --output           Where to place generated models
                            [default: "./output"]
  -s, --schema           Schema name to create model from. Only for mssql
                         and postgres. You can pass multiple values
                         separated by comma eg. -s scheme1,scheme2,scheme3
  --ssl                                               [boolean] [default: false]

在 package.json 中配置

ts
{
...
  "scripts": {
        "generator:models": "typeorm-model-generator -h yourHost -p 3306 -d yourDatabase -u username -x password -e mysql -o ./src/entities"

  },
...
}

使用

ts

pnpm run generator:models