环境变量

js-yaml配置

nestjs环境配置, 结合 js-yaml typeorm @nestjs/config mysql2 实现一个全局环境变量配置!
当然你也可以使用dotenv or cross-env来实现环境变量配置, 这里只是使用js-yaml来实现环境变量配置!

依赖包准备

1
pnpnm add @nestjs/typeorm typeorm mysql2 @nestjs/config js-yaml @types/js-yaml --save
依赖包描述
@nestjs/typeormnestjs 集成typeorm
typeorm一个用于TypeScriptJavaScriptORM
mysql2mysql的驱动程序
@nestjs/confignestjs 环境配置模块
js-yaml用于解析yaml格式的js库
@types/js-yaml类型定义文件, 可以友好提示代码!

配置文件准备

工程根目录创建文件config -> config.dev.yamlconfig -> config.prod.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
app:
port: 3000
env: development
secret: nest-demo-secret
# 日志配置
log:
level: debug
dir: logs
file: nest.log
max_size: 100m
max_files: 10
# 数据库配置
db:
mysql:
type: mysql
host: **.***.***.***
port: 3306
username: your_username
password: your_password
database: database_name
# 实体类字段映射同步
synchronize: true,
# 自动加载实体类
autoLoadEntities: true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
app:
port: 3000
env: development
secret: nest-demo-secret
# 日志配置
log:
level: debug
dir: logs
file: nest.log
max_size: 100m
max_files: 10
# 数据库配置
db:
mysql:
type: mysql
host: **.***.***.***
port: 3306
username: your_username
password: your_password
database: database_name
# 实体类字段映射同步
synchronize: true,
# 自动加载实体类
autoLoadEntities: true

配置文件解析

创建文件utils -> config.util.ts,文件内容用来解析yaml返回配置对象!

1
2
3
4
5
6
7
8
import { readFileSync }  from 'fs';
import { join } from 'path';
import * as yaml from 'js-yaml';

const env = process.env.NODE_ENV || 'dev';
const config = () => yaml.load(readFileSync(join(__dirname, `../../config/config.${env}.yaml`), 'utf8'));

export default config;

process.env.NODE_ENV 需要在scripts脚本中需要手动进行配置否则无法获取到!

package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
"scripts": {
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "NODE_ENV=dev nest start",
"start:dev": "NODE_ENV=dev nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "NODE_ENV=prod node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
},

"start": "NODE_ENV=dev nest start",
"start:dev": "NODE_ENV=dev nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "NODE_ENV=prod node dist/main",

配置typeorm

app.module.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './modules/user/user.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule, ConfigService } from '@nestjs/config';
import config from './utils/config';
@Module({
imports: [
UserModule,
/* TypeOrmModule.forRoot({
type:'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: 'root',
database: 'test',
// 实体类字段映射同步
synchronize: true,
// 自动加载实体类
autoLoadEntities: true,
}), */
TypeOrmModule.forRootAsync({
// 配置数据库连接
// 依赖注入 configService
inject: [ConfigService],
useFactory: (configService: ConfigService) => {
// 获取配置
const dbConfig = configService.get('db').mysql;
const isProd = process.env.NODE_ENV === 'production';
// console.log("dbConfig", dbConfig);
return {
type: dbConfig.type,
host: dbConfig.host,
port: dbConfig.port,
username: dbConfig.username,
password: dbConfig.password,
database: dbConfig.database,
// 实体类字段映射同步 生产关闭同步,放置字段同步引起数据丢失!
synchronize: !isProd,
// 自动加载实体类
autoLoadEntities: true,
};
},
}),
// 加载全局配置
ConfigModule.forRoot({
isGlobal: true,
load: [config]
})
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}

main.ts中使用

main.ts中加入以下代码!

1
2
const configService = app.get(ConfigService);
const port = configService.get('app');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { ConfigService } from '@nestjs/config';

async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 获取全局配置
const configService = app.get(ConfigService);
const port = configService.get('app').port || 3000;
/*
创建 swagger 文档
*/
const options = new DocumentBuilder()
.setTitle('Nestjs Demo') // 设置 swagger doc 标题
.setDescription('The Nestjs Demo API description') // 设置 swagger doc 描述
.setVersion('1.0') // 设置 swagger doc 版本
.addTag('demo') // 设置 swagger doc 标签
.addBearerAuth() // 设置 swagger doc 认证方式
.build();

const document = SwaggerModule.createDocument(app, options);
SwaggerModule.setup('/doc/api', app, document);

await app.listen(port);
}
bootstrap();

dotenv配置

Dotenv 是一个零依赖的模块,它能将环境变量中的变量从 .env 文件加载到process.env 中。

安装依赖

1
pnpm add dotenv --save

创建env文件

在根目录中创建env文件!

1
2
3
4
5
6
7
8
9
10
// 数据库地址
DB_HOST=localhost
// 数据库端口
DB_PORT=3306
// 数据库登录名
DB_USER=root
// 数据库登录密码
DB_PASSWD=root
// 数据库名字
DB_DATABASE=blog
1
2
3
4
5
6
7
8
9
10
// 数据库地址
DB_HOST=localhost
// 数据库端口
DB_PORT=3306
// 数据库登录名
DB_USER=root
// 数据库登录密码
DB_PASSWD=root
// 数据库名字
DB_DATABASE=blog

配置scripts

"start": "NODE_ENV=dev nest start",
"start:dev": "NODE_ENV=dev nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "NODE_ENV=prod node dist/main",

配置config.util.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import * as fs from 'fs';
import * as path from 'path';
const isProd = process.env.NODE_ENV === 'production';

function parseEnv() {
const localEnv = path.resolve('.env.dev');
const prodEnv = path.resolve('.env.prod');

if (!fs.existsSync(localEnv) && !fs.existsSync(prodEnv)) {
throw new Error('缺少环境配置文件');
}

const filePath = isProd && fs.existsSync(prodEnv) ? prodEnv : localEnv;
return { path:filePath };
}
export default parseEnv();

上面的文件执行返回的是一个对象: { path:'环境变量文件' }

配置app.module.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigService, ConfigModule } from '@nestjs/config';
import envConfig from '../config/env';

@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true, // 设置为全局
envFilePath: [envConfig.path]
}),
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => ({
type: 'mysql', // 数据库类型
entities: [], // 数据表实体
host: configService.get('DB_HOST', 'localhost'), // 主机,默认为localhost
port: configService.get<number>('DB_PORT', 3306), // 端口号
username: configService.get('DB_USER', 'root'), // 用户名
password: configService.get('DB_PASSWORD', 'root'), // 密码
database: configService.get('DB_DATABASE', 'blog'), //数据库名
timezone: '+08:00', //服务器上配置的时区
synchronize: true, //根据实体自动创建数据库表, 生产环境建议关闭
}),
}),
PostsModule,
],
...
})
export class AppModule {}

加载配置文件

1
2
3
4
5
6
7
// 加载配置文件
require('dotenv').config({ path: '.env.prod' });
// 使用
console.log("process.env.NODE_ENV", process.env.NODE_ENV);
console.log(process.env.HOST) // localhost
console.log(process.env.PORT) // 3000
console.log(process.env.MONGOOSE_URL) // mongodb://localhost:27017/test