对于nestjs这个框架来说很早之前都想学习了。可是一直没有时间,最近时间比较充裕,就开启了nestjs的学习之路,也可以让自己以后向后端开发靠近。毕竟这个框架和其他后端语言的框架更贴切,而不像Koa. Express, Egg.js写起来那么随意。
nestjs同其他nodejs框架的优势
- 基础环境无需花时间准备,有CLI工具,开发效率高
- 无惧技术选型,更容易找到行业内的标杆或成熟方案
- 由于采用比较优秀的架构,扩展性更好,较低成本重构逻辑
- 代码架构合理,装饰器语法,概念比较多;
- TS原生支持,体验好,项目的代码质量高;
- 对于代码人员的要求更高,上手有难度(Egg.js/Express/koa)
nestjs架构
默认是通过express
提供http服务的,也可以选择高性能的fastify。
Nodejs框架特点对比
- koa实现web服务的特点
只实现了web服务,路由,日志,请求拦截器等需要自己实现。该库逻辑轻量,容易理解。
- eggjs实现web服务的特点
实现了路由和分层架构及CMD规范,但是它非ts编写,不利于大型项目的维护开发。
- nestjs实现web服务的特点
实现了路由和逻辑分层,并原生支持ts,内部封装了很多装饰器(注解)类似Java,可以让项目更健壮。
总结:
- Koa&Express本身只实现了HTTP服务,中间逻辑需自己实现。
- Egg.js有合理的逻辑分层,但TS支持不好。
- Nest.js生态最好,使用TS+注解的方式更便捷。并且官方提供了一个好用的脚手架,可以快速创建对应的层级模板,初始化一个完整的项目。
后端服务涉及的内容
nestjs初体验
创建项目
js
npm i -g @nestjs/cli
nest new <project-name>
利用nest提供的脚手架命令创建对应的功能模板
学习nestjs模板demo项目
js
npm install -g deget
deget 克隆仓库时,不会将git历史依赖克隆下来。
js
deget gitPath <dirname>
工程目录
代码调试
我们知道,在开发前端应用程序时只需要卸载debugger,即可在浏览器中进行debugger,但是对于后端程序来说,我们只能在编辑器中进行调试。
或者我们直接运行yarn start:debug
脚本,可以在浏览器中直接调试。
一些常见的编程名词
OOP 面向对象编程
将一个具体的事物拆分成一个个独立的对象,通过调用其中的方法去解决问题。有三种特性:封装,继承,多态。
FP 函数式编程
确定的输入有确定的输出,没有副作用。也是一种声明式编程,现在主流的前端框架都是这种方式。只关注结果不关注过程。
AOP 面向切面编程
扩展功能的一种方式,不影响原有功能。逻辑集中管理,更有利于代码复用。即能在不破坏封装功能的前提下额外增加新功能。
IOC 控制反转
将强依赖的内容抽离成一个参数传入,从而进行解耦。
DI 依赖注入
一种用于实现IOC的设计模式,他允许在类外创建依赖对象,并通过不同的方式将这些对象提供给类。
DTO 数据传输对象,DAO 数据访问对象
nestjs生命周期
核心概念
开发配置介绍
环境变量配置
- dotenv: 只能在配置文件中填写
key=value
形式,对于嵌套格式数据,不方便开发。更适合前端项目中多环境的配置。这个也是nestjs内部读取环境变量集成的库。 - config: 可以在
config/*
中写yaml,json等格式的配置文件,解析时可以直接读取嵌套结构属性。更适合后端项目中多环境的配置。
nestjs内部环境配置
- 安装
@nestjs/config
- 文件根目录下配置环境变量文件
.env.*
- app.module.ts中使用
js
import { ConfigModule } from '@nestjs/config';
@Module({
// 导入模块
// ConfigModule.forRoot 加载环境变量
imports: [
ConfigModule.forRoot({
// 将环境变量在全部文件模块中导入
isGlobal: true,
}),
UserModule,
],
// 注册控制器
controllers: [AppController, UserController],
// 依赖注入,在控制器中自动实例化该服务
providers: [AppService, UserService],
})
- 使用
js
import { ConfigService } from '@nestjs/config';
// 依赖注入,自动实例化
constructor(
private userService: UserService,
private config: ConfigService,
) {}
const envConfig = this.config;
console.log('db, db_url', envConfig.get('DB'), envConfig.get('DB_URL'));
根据运行环境来加载不同配置文件。
- 我们需要借助
cross-env
库来帮助我们修改nodejs运行的环境变量。 - 通过
process.env
去读取NODE_ENV
变量,当前运行的是哪个环境。 - 通过
nestjs
config配置属性envFilePath
来设置对应的环境变量文件路径。
js
import { ConfigModule } from '@nestjs/config';
const envFilePath = `.env.${process.env.NODE_ENV || 'development'}`;
@Module({
// 导入模块
// ConfigModule.forRoot 加载环境变量
imports: [
ConfigModule.forRoot({
// 将环境变量在全部文件模块中导入
isGlobal: true,
// 设置读取的环境变量文件
envFilePath,
}),
UserModule,
],
// 注册控制器
controllers: [AppController, UserController],
// 依赖注入,在控制器中自动实例化该服务
providers: [AppService, UserService],
})
- 修改运行的脚本命令
js
"start:dev": "cross-env NODE_ENV=development nest start --watch",
"start:prod": "cross-env NODE_ENV=production node dist/main",
提取通用配置,否则在一些特定配置需要写多次。
- 安装
dotenv
包来加载.env
文件并解析。 - 通过
nestjs
config配置属性load
来加载自定义环境变量。
js
import { ConfigModule } from '@nestjs/config';
import * as dotEnv from 'dotenv';
const envFilePath = `.env.${process.env.NODE_ENV || 'development'}`;
@Module({
// 导入模块
// ConfigModule.forRoot 加载环境变量
imports: [
ConfigModule.forRoot({
// 将环境变量在全部文件模块中导入
isGlobal: true,
// 设置读取的环境变量文件
envFilePath,
// 加载自定义配置文件数组。这里可以加载提取出的相同配置文件属性
load: [() => dotEnv.config({ path: '.env' })],
}),
UserModule,
],
// 注册控制器
controllers: [AppController, UserController],
// 依赖注入,在控制器中自动实例化该服务
providers: [AppService, UserService],
})
以上就是在开发中使用最多的读取配置环境的情况了。
嵌套设置环境变量,减少代码冗余。这种只适合配置文件特别复杂的情况下。
- 可以通过
js-yaml
库解析yaml文件,然后加入到nestjs
config配置属性load
来加载自定义环境变量。 - 也可以直接使用第三方零配置库
config
进行读取。
使用,他会根据NODE_ENV
环境的不同去合并default.json
和对应环境的json
文件。并且他也会自动解析yaml
后缀的文件。
js
import * as config from 'config';
console.log('====config', config.get('db.db_url')); // 类似于lodash的get方法
验证配置参数
其实这块也不需要校验啥,配置都是开发者自己设置的,一般不会改动。为了项目更健壮,做一些校验也未尝不可。
官方推荐使用joi
库进行校验。结合nestjs
config配置属性validationSchema
进行校验。 注意他只能验证envFilePath
加载的配置文件,不能验证load
加载的配置。
js
import { ConfigModule } from '@nestjs/config';
import * as dotEnv from 'dotenv';
import * as Joi from 'joi';
const envFilePath = `.env.${process.env.NODE_ENV || 'development'}`;
@Module({
// 导入模块
// ConfigModule.forRoot 加载环境变量
imports: [
ConfigModule.forRoot({
// 将环境变量在全部文件模块中导入
isGlobal: true,
// 设置读取的环境变量文件
envFilePath,
// 加载自定义配置文件数组。这里可以加载提取出的相同配置文件属性
load: [() => dotEnv.config({ path: '.env' })],
// 验证环境变量(只能验证特定环境的配置文件,不能验证load中加载的)
validationSchema: Joi.object({
// 验证DB_PORT变量,并设置默认值为3306
DB_PORT: Joi.number().valid(3306),
}),
}),
UserModule,
],
// 注册控制器
controllers: [AppController, UserController],
// 依赖注入,在控制器中自动实例化该服务
providers: [AppService, UserService],
})
以上就是nestjs开发的简单总结,这里需要感谢Brian老师。