你认为Vonajs提供的这些特性会比Nestjs更好用吗?
Nestjs是一款非常强大的Node.js框架,而且入门非常容易,但是随着项目的增长,各种不便之处就会显现出来,许多代码书写起来不再像项目刚启动时直观。而Vonajs是一款全新的Node.js框架,提供了许多创新性的架构设计,让我们在开发任何规模的项目时,代码都能保持直观和优雅。下面,我们一起来看看这些特性,是否真的比nestjs更好用?
特性
| 特性 | Vona | Nest |
|---|---|---|
| Typescript | ||
| 模块化体系 | scope对象:config/locale/service | |
| 全量esm模块 | commonjs | |
| Ioc容器 | 依赖注入、依赖查找 | |
| bean配置 | ||
| bean全局单例 | 节约内存 | |
| 多租户 | ||
| 多数据库、多数据源 | ||
| 数据库事务 | ||
| cli命令 | ||
| 菜单命令 | ||
| env:环境变量 | 多维配置,开箱即用 | |
| config | 多维配置,开箱即用 | |
| 单文件打包、集群部署 | 开箱即用 | |
| aop:前置切面: Middleware/Guard/Pipe/Interceptor/Filter | 系统中间件、全局中间件、局部中间件 | |
| aop:主体切面: @AopMethod | ||
| aop:客体切面: @Aop | ||
| ssr聚合 | ||
| demo练习场 | REPL |
Typescript
Typescript现在已经是开发Node.js框架的标配技能了,勿须多言。
模块化体系
Vona和Nest都提供了模块化体系,而Vona还提供了scope机制。也就是为每个模块提供了一个scope对象,通过scope对象可以非常方便的访问模块的各类资源和能力。限于篇幅,这里仅对config/locale/service加以举例说明:
1. config
首先,在模块的config文件中添加配置项:
src/module/demo-student/src/config/config.ts
export function config() {
return {
+ title: 'hello world',
};
}
然后,在模块的controller中使用config配置,支持类型提示:
src/module/demo-student/src/controller/student.ts
export class ControllerStudent {
async findAll() {
+ console.log(this.scope.config.title);
}
}
2. locale国际化
首先,在模块的locale文件中添加国际化语言资源:
src/module/demo-student/src/config/locale/en-us.ts
export default {
+ Name: 'Name',
};
src/module/demo-student/src/config/locale/zh-cn.ts
export default {
+ Name: '名称',
};
然后,在模块的controller中使用国际化语言资源,支持类型提示:
src/module/demo-student/src/controller/student.ts
export class ControllerStudent {
async findAll() {
+ console.log(this.scope.locale.Name()); // 根据环境值自动翻译为指定的语言
+ console.log(this.scope.locale.Name.locale('en-us')); // Name
+ console.log(this.scope.locale.Name.locale('zh-cn')); // 名称
}
}
3. service
首先,在模块中定义一个student service:
src/module/demo-student/src/service/student.ts
@Service()
export class ServiceStudent {
async findAll() {
return await this.scope.model.student.select();
}
}
然后,在模块的controller中直接使用student service,支持类型提示:
src/module/demo-student/src/controller/student.ts
export class ControllerStudent {
async findAll() {
+ return await this.scope.service.student.findAll();
}
}
全量esm模块
Nest由于开发得比较早,因此仍然采用的是commonjs模块。而Vona是全新的框架,所以全量采用esm模块,项目启动更快。
Ioc容器
Vona和Nest都提供了Ioc容器,而Vona提供了更加快捷的容器操纵能力。我们知道Ioc容器主要提供两个操作:注册bean和获取bean。获取bean有两种方式:依赖注入、依赖查找。Vona不仅支持依赖注入,同时也提供了依赖查找,使代码书写更加直观、优雅。这里简要演示全局bean和本地bean的依赖查找:
- 获取全局bean:jwt,并调用create方法:
export class ControllerStudent {
async findAll() {
+ const accessToken = await this.bean.jwt.create();
}
}
- 获取本地bean:student,并调用findAll方法:
export class ControllerStudent {
async findAll() {
+ return await this.scope.service.student.findAll();
}
}
bean配置
在Ioc语境当中,bean就是可以注入的class,包括controller、service、middleware、guard、interceptor、pipe,filter,等等。Vona提供了一个通用的机制,让我们可以为所有bean提供动态配置能力,从而显著提升整个系统的扩展性,也能够节约大量的与配置相关的代码。下面我们以middleware为例,来演示如何进行bean配置
1. 创建一个middleware
src/module/demo-student/src/bean/middleware.test.ts
export interface IMiddlewareOptionsTest {
+ title: string;
}
@Middleware<IMiddlewareOptionsTest>({
+ title: 'hello world',
})
export class MiddlewareTest {
async execute(options: IMiddlewareOptionsTest, next: Next) {
+ console.log(options.title);
// next
return next();
}
}
- 行2:定义一个参数title
- 行6:为参数提供缺省值
- 行10:在实际代码当中直接读取配置选项
2. 使用middleware,并传参
export class ControllerStudent {
+ @Aspect.middleware('demo-student:test', { title: 'hello world!!' })
async findAll() {
}
}
- 行2:使用装饰器@Aspect.middleware,传入middleware的名称:demo-student:test
- 同时可以传入新的参数配置,覆盖默认值
3. 通过项目Config来修改middleware配置
src/backend/config/config/config.local.mine.ts
export default function () {
const config = {} as VonaConfigOptional;
// onions
config.onions = {
middleware: {
+ 'demo-student:test': {
+ title: '您好世界!!',
+ },
},
};
- 直接在系统Config文件中修改中间件的参数配置,支持类型提示
bean全局单例
一般而言,bean的实例化有三个层级:全局单例、Request单例、总是创建新实例。全局单例是最节约内存的。Request单例,有多少用户请求,就要创建多少个bean实例。比如,执行一个完整的api请求需要创建2个bean实例,如果1秒中有1万个请求,那么就需要创建2万个bean实例,对内存的占用非常高,也会严重影响gc的性能。可想而知,采用全局单例还是采用Request单例对系统性能的影响是非常显著的。
Nest对bean实例化有特殊的处理机制:在默认情况下,Controller/Service是全局单例的,但是,如果在代码中注入了与Request相关的对象,那么这些bean就会降级到Request单例。可想而知,在一个实际的业务系统中,基本上这些bean都会访问与Request相关的数据,所以基本上都是按Request单例实例化的。与Request相关的数据包括:当前语言、当前用户、当前租户,等等。
而Vona则是实现了完整的全局单例机制。即便这些bean实例访问了Request相关的对象,也不会降级。从原理来说,Vona底层采用了Async Local Storage机制,从而让整个系统的内存占用非常低,也能显著改善gc的性能。
多租户
Nest本身没有提供多租户的能力,社区有一些多租户的方案,但是代码不够简洁。而Vona则内置了多租户的能力,让代码更加简洁。
src/module/demo-student/src/service/student.ts
export class ServiceStudent {
async findAll() {
+ return await this.scope.model.student.select();
}
}
- 行3:这行代码就是查询当前租户下的所有学生信息
- 由此可见,租户能力是完全透明的
多数据库、多数据源
Vona和Nest都支持多数据库、多数据源。此外,Vona还提供了开箱即用的读写分离和动态数据源能力。下面我们看一下在Vona中的代码体验:
1. 数据源配置
{
defaultClient: 'pg', // 缺省数据源
clients: { // 所有数据源清单
pg: {
client: 'pg', // 所使用的数据库方言
connection: {...},
},
mysql: {
client: 'mysql2',
connection: {...},
},
},
}
2. 使用数据源
// 获取缺省数据源
const db = app.bean.database.current;
// 创建其他数据源
const dbMysql = app.bean.database.createDb({ clientName: 'mysql' });
数据库事务
Nest本身不考虑数据库事务的问题,而是由第三方库来提供。而Vona则内置了数据库事务。
1. 使用装饰器
export class ControllerStudent {
+ @Database.transaction()
async update() {
}
}
2. 手动启用
export class ControllerStudent {
async update() {
+ const db = app.bean.database.current;
+ const result = await db.transaction.begin(async () => {
+ const data = await dosomething();
+ return data;
+ });
}
}
3. 数据库事务传播机制
Vona支持事务传播机制的设置,通过 propagation 属性来指定传播行为。Vona事务传播机制有以下 7 种:
- Propagation.REQUIRED: 默认的事务传播级别. 如果当前存在事务, 则加入该事务. 如果当前没有事务, 则创建一个新的事务
- Propagation.SUPPORTS: 如果当前存在事务, 则加入该事务. 如果当前没有事务, 则以非事务的方式继续运行
- Propagation.MANDATORY: 强制性. 如果当前存在事务, 则加入该事务. 如果当前没有事务, 则抛出异常
- Propagation.REQUIRES_NEW: 创建一个新的事务. 如果当前存在事务, 则把当前事务挂起. 也就是说不管外部方法是否开启事务, Propagation.REQUIRES_NEW 修饰的内部方法都会新开启自己的事务, 且开启的事务相互独立, 互不干扰
- Propagation.NOT_SUPPORTED: 以非事务方式运行, 如果当前存在事务, 则把当前事务挂起(不用)
- Propagation.NEVER: 以非事务方式运行, 如果当前存在事务, 则抛出异常
- Propagation.NESTED: 如果当前存在事务, 则创建一个事务作为当前事务的嵌套事务来运行.如果当前没有事务, 则该取值等价于 PROPAGATION_REQUIRED
cli命令
Vona和Nest都提供了大量cli命令,用于生成各类资源的代码骨架。
菜单命令
Vona在cli命令的基础上提供了大量菜单命令,通过菜单来执行cli命令,从而显著降低心智负担,提升开发体验:
1. Vona Bean

2. Vona Create

3. Vona Init

4. Vona Meta

5. Vona Tools

env:多维配置
Vona提供了env的多维配置能力,支持更复杂的业务场景。
在默认情况下,可以在Vona中提供三个场景的env配置文件:
.env // 缺省配置
.env.test // 测试环境
.env.local // 本地开发环境
.env.prod // 生产环境
如果我们想针对业务的需要新增更多场景的env配置,如何操作呢?Vona引入了flavor的概念。比如,我们新增一个flavor,名称为stage1,那么,env配置文件如下:
.env.stage1 // stage1的缺省配置
.env.stage1.test // stage1的测试环境
.env.stage1.local // stage1的本地开发环境
.env.stage1.prod // stage1的生产环境
Config:多维配置
Vona同样也提供了Config的多维配置能力,支持更复杂的业务场景。
config.ts
config.test.ts
config.local.ts
config.prod.ts
# flavor: stage1
config.stage1.ts
config.stage1.test.ts
config.stage1.local.ts
config.stage1.prod.ts
单文件打包、集群部署
Vona提供了开箱即用的单文件打包和集群部署能力。Nest虽然也能支持这些能力,但是仍然需要花点功夫进行配置。
1. 单文件打包
$ npm run build
- 执行此命令,将在dist目录生成唯一的js文件
2. 集群部署
$ npm run start
- 执行此命令,将基于cpu数量启动多个进程,进行集群部署
2. 单进程模式
$ npm run start:one
- 执行此命令,将启动单进程,可直接用于docker环境
aop:面向切面编程
在Vona中,将aop编程能力分为三个层次:前置切面、主体切面、客体切面。
1. 前置切面
前置切面,就是在执行Controller Action之前切入逻辑,包括:Middleware、Guard、Pipe、Intercepter,Filter,等等。
2. 主体切面
主体切面,就是在任何Class的任何Action之前切入逻辑。比如,我们为更新数据的方法切入一个数据库事务:
export class ControllerStudent {
+ @Database.transaction()
async update() {
}
}
3. 客体切面
客体切面,就是在不改变源码的前提下,在任何Class的任何Action之前切入逻辑:
首先,我们先定义一个bean:
@Bean()
export class BeanTest {
actionSync() { }
async actionAsync() { }
}
然后,创建一个aop bean:
@Aop({ match: 'test')
export class AopTest {
actionSync(_args, next) {
const result = next();
return result;
}
async actionAsync(_args, next) {
const result = await next();
return result
}
}
- 行2:定义一个aop bean
- 行1:通过match参数,将AopTest与BeanTest建立关联
- 当系统在执行BeanTest的方法时,会自动将AopTest提供的方法切入
- 支持同步方法和异步方法
ssr聚合
现在ssr渲染很火,但往往用于信息展示类的前台网站,后台admin系统则很少采用,主要原因就是整合有点难度,需要考虑的边界问题比较多,性价比不高。但是,Vona提供了开箱即用的ssr渲染能力,同时支持前台网站,和后台admin系统。
demo练习场
在实际开发当中,我们经常需要写一些临时代码,对一些想法和思路进行验证和评估。Nest提供了REPL机制,采用命令行交互模式。Vona专门提供了demo练习场,让我们可以非常方便的进行代码演练。下面,我们简要演示一下:
1. 书写demo
src/backend/demo/index.ts
export async function main(app: VonaApplication, argv: IArgv) {
... do something
}
- 通过app可以调用系统所有能力
- 通过argv接收命令行参数
2. 执行demo
$ npm run demo
- 执行此命令,就会自动初始化一个
app实例,然后执行demo/index.ts文件的main方法
结语
Vonajs作为全新的Node.js框架,顺应技术趋势,大胆使用新技术,提出了许多新的架构设计思路,通过一系列的微创新,解决开发当中的痛点问题,让我们的代码更加直观、优雅,从而能轻松应对大型项目的开发与维护。通过对Vonajs特性的简要介绍,大家是否认为会比nestjs更好用呢?
欲了解更多有关Vonajs的信息,参见B站:濮水代码
你认为Vonajs提供的这些特性会比Nestjs更好用吗?的更多相关文章
- 趋势:Chrome为打包应用提供强大新特性
Chrome 7月9日刚为Chrome打包的应用提供了强大的访问Google服务例如Google统计.GoogleAPI和Google 钱包的能力,除此之外,还能够使用系统层面的服务包括蓝牙和原生应用 ...
- Atitit.eclise的ide特性-------abt 编译
Atitit.eclise的ide特性-------abt 编译 为什么要在Intellij IDEA中使用Eclipse编译器 如果你使用Intellij Idea,你应该考虑使用Eclipse编译 ...
- 服务器RAS性能
服务器的安全性能要求非常高,主要体现在RAS性能上.RAS性能指的是机器的可靠性(Reliability).可用性(Availability)和可服务性(Serviceability).RAS能力主要 ...
- 采访ServiceStack的项目领导Demis Bellot——第1部分(网摘)
ServiceStack是一个开源的.支持.NET与Mono平台的REST Web Services框架.InfoQ有幸与Demis Bellot深入地讨论了这个项目.在这篇两部分报道的第1部分中,我 ...
- 采访ServiceStack的项目领导Demis Bellot——第1部分(转)
ServiceStack是一个开源的.支持.NET与Mono平台的REST Web Services框架.InfoQ有幸与Demis Bellot深入地讨论了这个项目.在这篇两部分报道的第1部分中,我 ...
- Oracle 11g 执行计划管理1
1. 执行计划管理的工作原理 1.1控制执行计划的稳定性 11g之前,可以使用存储大纲(stored outline)和SQL Profile来固定某条SQL语句的执行计划,防止由于执行计划发生变化而 ...
- 35.Intellij IDEA设置忽略部分类编译错误
转自:https://www.aliyun.com/jiaocheng/290360.html 有些时候我们的项目中有些错误,但这些错误并不影响项目的整体运行(或许是没有使用到),默认情况下idea是 ...
- 为互联网业务而生:阿里云全球首发云Cassandra服务!
引言:十年沉淀.全球宽表排名第一.阿里云首发云Cassandra服务 ApsaraDB for Cassandra是基于开源Apache Cassandra,融合阿里云数据库DBaaS能力的分布式No ...
- Intellij IDEA设置忽略部分类编译错误
有些时候我们的项目中有些错误,但这些错误并不影响项目的整体运行(或许是没有使用到),默认情况下idea是无法通过编译的,因此也就无法部署运行,要达到正确运行项目的目的需要作一些设置才行. 设置Inte ...
- MVC特性路由的提供机制
回顾:传统路由是如何提供的? 我们知道最终匹配的路由数据是保存在RouteData中的,而RouteData通常又是封装在RequestContext中的,他们是在哪里被创建的呢?没错,回到了UrlR ...
随机推荐
- Java 设计模式:装饰者模式(Decorator Pattern)
一.模式定义 装饰者模式属于结构型设计模式,允许通过动态包装对象的方式为对象添加新功能,提供比继承更灵活的扩展方式.该模式通过组合替代继承,遵循开闭原则(对扩展开放,对修改关闭). 二.核心角色 Co ...
- Raft学习笔记
0.前言 Raft 作为一种强一致性的共识算法,被广泛应用于分布式系统中,如 etcd.Consul 等.最近阅读了一篇关于 Raft 的技术文章,收获颇多,因此写下此学习笔记,记录其中的关键概念与个 ...
- Linux下对LVM逻辑卷分区大小调整 [针对xfs和ext4文件系统]
当我们在安装系统的时候,由于没有合理分配分区空间,在后续维护过程中,发现有些分区空间不够使用,而有的分区空间却有很多剩余空间.如果这些分区在装系统的时候使用了lvm(前提是这些分区要是lvm逻辑卷分区 ...
- The surprising impact of mask-head architecture on novel class segmentation精讲
目录 Mask RCNN Problem Definition Key idea Only Mask Head Code Summary Refer 大家好,这是我今天要讲的论文,它是2021年发表在 ...
- Qt/C++开发经验小技巧311-315
关于流媒体推拉流延时的几点说明. 经常看到一些流媒体相关的程序,号称零延迟,不用怀疑,这肯定吹牛逼的. 搞音视频开发,有个核心的指标就是实时性,也就是延迟多少毫秒,这个问题问的也是最多的. 音视频文件 ...
- Javascript 对象(object)合并
转
转载了一篇介绍的比较直观的博文.
- leetcode每日一题:监控二叉树
引言 今天的每日一题原题是2643. 一最多的行,直接模拟,切除和最大的一行即可.更换成前几天遇到的更有意思的一题来写这个每日一题. 题目 968. 监控二叉树 给定一个二叉树,我们在树的节点上安 ...
- 面试题:Linux 系统基础 (二)
Linux系统中的定时任务有哪些类型,它们是如何配置的? Linux系统中的定时任务主要有两种类型:Cron作业和at作业. 1.Cron作业: 使用crontab命令配置和管理. 配置周期性执行的任 ...
- CAS前后端分离解决方案
CAS前后端分离解决方案 关于CSS服务器的搭建和整合SpringBoot参考:CAS5.3服务器搭建与客户端整合SpringBoot以及踩坑笔记 环境与需求 后端:springboot 前端: vu ...
- Windows IntelliJ IDEA 快捷键终极大全
自动代码 常用的有fori/sout/psvm+Tab即可生成循环.System.out.main方法等boilerplate样板代码 . 例如要输入for(User user : users)只需输 ...