phecda-server
一款易于接入、可复用类型的类nestjs
服务端框架
intro
我不需要一个玩具
很多开源的服务端框架有很棒的性能和特性,但实际上,社区里的实践多是一些无关轻重的项目,或许未来会成为主流技术,但当下看起来更像是一个花哨有趣的玩具。
但我真正需要的,是一个能让我无后顾之忧地在现有项目中使用的技术
我希望有一款服务端在个人、企业、或大或小的项目...无论在任何时候都能帮上忙
它以实用为第一且唯一的目标,而不是为开发者提供想象空间,坦率地说,相较于其他任何框架,这都是一个极度乏味的方案,
很多优秀的开源方案会强调的部分,比如体积和压测,PS
不关心
虽然确实依赖少体积小,但这并不是目的,如果有必要的话,我会毫不犹豫膨胀体积
性能与使用的框架有关,目前从压测看会比原有的框架并发少 20%(这看上去是个很恐怖的数字,但鉴于
benchmark
的猫腻,实际业务的影响几乎没有), 我会尽力让性能维持在当前的水平上,但不会花时间做一个提高性能百分之 x 的改动
PS
更重视维护性、可读性、开发体验、代码量...一些业务中真正能让开发者受益的东西
类nestjs
的写法
沿用了一部分nestjs
的模式:
- 以类为核心的写法能提供比较规范的格式和不错的可读性
- 利用元数据实现的控制反转能提供很棒的体验,
aop
也能帮助注意力集中在业务本身上
但nestjs
可能导致代码冗余和理解困难的特性,如过于灵活的依赖注入和兼容,这些部分会移除
总之,只使用了我认为好用的部分
类nestjs
只是为了方便理解,体验也有相似之处,但本质大相径庭,如果开发者坚信诸如“模块级+花样繁多的注入”“请求级的生命周期” 有巨大意义,那么PS
绝对是来添乱的
易于接入
易于接入和易于移植并不是同一回事
易于移植并不是完全意义的好事,因为真实的项目大部分时候不会无端的移植,
为什么要花时间将一个无比稳定的 express
应用用 hono
重写一遍?即使这样做很容易
真实的情况是,我可能要接着开发这个 express
应用,提供的新接口显然也要是一个express router
,新模块要能调用旧模块,甚至旧模块要能调用新模块,很多时候只能捏着鼻子接着用 express
的思路做
最好的情况是,新模块本质是一个 express
的一部分,那么一切问题都会引刃而解。
ps
就是这么做的,出于这个特点,ps
能支持各种服务端以及微服务
ps
能接入绝大部分底层服务端框架,但对于依赖编译工具的高级框架,如nextjs/nitro
等则不行我承认至少一部分框架是需要支持的,(好吧其实就只有
nextjs
),但这工作量对我实在是过于残忍,且本人对
nextjs
有极大恶意,故不打算支持
INFO
这和nestjs
也不太一样(虽然其也号称progressive
, 但我相信不会真有人这么用的)
nestjs
侧重于使不同框架作为其底层的运行时
由于上层设计过重,nestjs
很难去“迁就”底层服务框架,结果就是官方无力兼容express
以外的东西,甚至连fastfiy
的特性都遗失了不少
而ps
则更像是对原有框架的加强
上述两点足够让内部代码较为糟糕的团队心动, 但如果你是一位技术的狂信徒,可能确实需要一个强而有力的 feature
说服自己,那PS
也提供了一些吸引眼球的特性
PS
提供了不少实用且独特的功能,但只有这两个功能称得上绝无仅有
代码和类型的复用
好吧,也可以叫端到端类型安全
我不太确定其他开发者对类型复用的理解是什么, 我的理解大概是有两个步骤
声明类型
使用特定的请求库,复用这个类型
可能在此基础上还有一些区别,比如:
如何声明类型的,是通过zod
等方式隐式推导类型还是通过单独显式声明?是完全通过类型推导去区分method/query/body/params
,如elysia
,还是完全不区分,直接写死标准?(全部使用POST
请求,并将数据挂到body
),如trpc/tsrpc
无论是写死标准还是使用特定请求库,都不一定是好事:
你真的确定手头的项目可以完全舍弃
restful
标准吗使用大量类型体操可能导致
ide
卡顿或对眼睛不友好(可以看一下elysia
的类型)
在服务端编写一些代码,生成一些代码,然后想办法让前端请求库在类型上复用代码类型,在调用上利用元数据(对应phecda-client
库)
将易接入性延续至客户端,包装axios/alova
而非自行制作请求库(phecda-server
/express
<==>phecda-client
/axios
)
不会影响业务中旧有的任何写法,成本低,过程透明
如果业务原有的请求库不是
axios
(真是羡慕...)可以自行包装一个,这很简单,代码一百行以内就能搞定
极速的热更新
现在的热更新,多是通过启动一个守护进程,当代码更新时,守护进程杀死原进程并启动一个新进程,并重新建立数据库连接等。
即使使用swc
等来编译,进程重启的过程仍然漫长
ps
实现文件级别的热更新(如同vite
中做的一样),文件更新时替换对应的模块,进程无需重启,再搭配swc
,可以实现<0.1s
的热更新
我还是要强调:这是小于零点一秒的热更新!开发体验绝对是极致中的极致了