1290年了,使用TypeScript来代替Javascript来构建我们的前后端应用,已经在社区达成共识,去年在新浪移动大前端团队,也积极的投入到了TypeScript的学习和开发之中来。
经过大概半年多的业务迭代,我们内部从一开始就计划开发一款拥有完整TypeScript开发体验的Nodejs Web框架。
经过几个版本的迭代后,我们终于开源了团队的内部web框架,Daruk。
Daruk是一款基于 Koa2,使用 typescript 开发的轻量级 web 框架。使用过 koa2 框架的朋友应该知道,koa2 属于比较原始和基础的 http server 实现,在日常的开发工作中,我们可能需要通过安装很多开源的中间件,自己完成复杂的项目配置,路由管理,以及和业务无关的工作:如日志,监控,性能等基础组件的定制。
目前内部已经有大概10几个web项目在使用Daruk来构建了,比如下面这个c端的产品:
手机新浪网的高清图整站(目前落地页100% Daruk,使用TypeScript开发),频道首等其他页面还在灰度中(原来是PHP项目),流量一天1500-2000万,QPS峰值700多。
Daruk自身的定位是Koa2的上层封装,所以团队中熟悉Koa开发和TS的都可以直接无门槛上手,基于约定的目录配置和周边的一些内部扩展(内部一些基础扩展还未全部开源),目前我们大前端团队已经开始承接手机新浪网的BFF层开发。
回到框架本身,在一开始去年设计的时候我们还不知道有nestJs还有midwayjs这些优秀框架,今年了解到之后,我们后期也会借鉴和吸收他们的一些特性和优点进行改进。
但是Daruk的Goal,从一开始的定位和之后的定位都不会变:轻巧的,易扩展的,面向对象式的MVC web框架,并拥有TS的完整开发体验。
Daruk这个名字是我起的,当时沉迷塞尔达传说不能自拔,你看就是这个家伙:
当然,Daruk上手也非常简单,我们也提供了对应的脚手架工具,帮助不熟悉ts的同学可以快速玩起来:
下面是一个常见的 Koa 服务代码:
// index.js
const Koa = require("koa");
const app = new Koa();
app.use(async ctx => {
ctx.body = "Hello World";
});
app.listen(3000);
转换成 Daruk 编写的例子如下:
// src/index.ts
import { Daruk } from "daruk";
let app = new Daruk("myapp", {
rootPath: __dirname, // 指定 autoloader根目录
debug: true // 开启调试模式
});
app.run(3000);
controllers的定义:
// src/controllers/index.ts
import { BaseController, Context, get } from "daruk";
export default class Index extends BaseController {
@get("/")
public async index(ctx: Context, next: Function) {
ctx.body = "Hello world";
}
}
更多详细使用方法,可以参考文档:
最后,由于目前项目刚刚开源,网站的文档核心部分已经编写完成,但是后边的框架设计和最佳实践还没有全部完善,近期几周会以单独文章的形式投稿在我们自己的前端专栏,同时也希望喜欢TS的Nodejs开发者们多多支持,一起参与。
:)
喜欢可以star呀~ 🌟
手机新浪网的高清图整站(目前落地页100% Daruk,使用TypeScript开发),频道首等其他页面还在灰度中(原来是PHP项目),流量一天1500-2000万,QPS峰值700多。
鸟哥的PHP还是被干了
🐂
点赞👍很轻量.,但是为什么要集成ejs呢,如何前后端分离开发呢,或者使用ssr
@zy445566 并不是啦,php下沉到更底层的服务或者去开发go服务,我们接管BFF而已,目前来看,效率和性能都有提升,当然这里面也有重构的功劳。总之,互相不冲突。
@yanqi321 只是脚手架里做了对应配置,daruk本身是没有提供ejs的哈,也可以不用,或者换别的。
已star
QPS峰值才700多?,看来我做过一万五峰值的项目能吹很多年了
@xiaojue https://docs.nestjs.com/ 为何不直接考虑 nest.js ,阿里也是学习 nest.js ,出了 midway
@zengming00 业务场景不一样的哈,我只是说一下实际情况,这个量确实不大哈,大了加机器,加机器 😂
@zuohuadong 我是这么想的,ts不光是只有装饰器,nest太依赖装饰器,当然我不是说装饰器不好,只是可能个人偏好上我更喜欢oop,但是我们下一个版本也会开始丰富我们的装饰器,初衷写这个框架的目的有一个点是为了让用习惯express和koa的同事能无成本的切换ts,不需要强行去接受AOP那些概念。
@zengming00 主要是量大的老板也不敢让我们直接上,这算是拿nodejs第一次在我们那边做c端的尝试吧。
@xiaojue 所有程序的最终实践还是 ror 和 spring 那套,大型项目必然会走向 AOP 。 php 的 swoft , node 的 nest.js ,go 的iris … 阿里 midway 学了nest.js 、 loopback4 也是学nest 重构了 。 只要用 ts , 就会发现nest 是真的把 ts 用到了极致,而且跟 angular 通用。 我们现在也是,招 javaer 来做 nest ,很方便,没spring boot 那么啰嗦,开发效率高,性能又好。 要说问题的话,可能是 分布式事务了。 node 多年来一直没在后端领域有大的建树,一定程度上归咎于框架,express/koa 这些在常规后端来看,就是工具,谈不上框架。 基于 nest.js 做二次开发其实比较合适, nest 的适配器可以换成 fastify 提高性能。
棒棒哒,终于等出来了,粗看了一些,koa上的ts封装,有一定扩展性,持续关注
@zuohuadong 老哥 问“为何不直接考虑 nest.js”这就有点杠精了
人家做的这套框架说不定和nestjs是同时起步的。 然后已经有业务落地了, 所以现在有了nestjs 就要把以前的成果扔掉重构?
@zuohuadong 我看介绍说midway是阿里内部沉淀很久了吧.
@tao1991123 midway 比 nest.js 早那么多年,新版本也是重构了。 loopback4 也是,我觉得一定程度上确实能说明 nest.js 这玩意确实有价值。 要不然也不会那么多项目在后来考虑 ts 重构的时候都想学 nest
@xiaozhongliu 是,然后18年的新版本是重构后的,之前版本完全不一样。
已star
@zuohuadong 嗯 每个框架出生的时候都有自己的使命和任务,如果nest是最终的解决方案,那么大家在实践中就会不约而同的像他靠齐。
但是自己开发一个公司内部的基础框架,考虑的不仅仅是你说的那几点,为什么阿里会自己开发midway而不是直接选择nest,很大的一个原因是可控,可快速响应,对内白盒,我们当时的考虑也有很大一部分是因为这个。
我还没有仔细读nest的源码,也许最终也会 “借鉴” 一些它的优点,但是如果我纯换nest,日后我想给框架增加一些其他features就很困难了。
这个世界不是一个非黑即白的选择题哈。
@i5ting 大佬求带。
@xiaozhongliu 沉淀了很久,我感觉主要是基建,开源其实并不久吧 - -。
@xiaojue 阿里midway 在 nest 之前就出来了,所以只是后面升级的时候参考了nest.js 。 AOP 这套思想本身就很灵活,方便后期加 features 。 基于 nest.js 二次开发也是一个选择。 说实话,我对大多数 noder 的印象还是觉得对架构和大型项目接触太少,很多都是从前端过来,如果接触多的话就像阿里一样,会有midway 这样的产品了。
@xiaojue 对, 前段时间开源大家都知道的.
@zuohuadong 二次开发和自主开发还是有差别。你说的大部分noder的问题我也同意,且行且珍惜吧,不挖坑怎么成长。😄
@zuohuadong 大厂要是不造轮子,哪里来的 kpi
持续关注~
@xiaojue 其实想着你们要是能把这块做好,没准能换掉 yaf ,哈哈~
目前感觉无论是 Spring Boot 还是 Nest.js、Egg.js 等都有点重,这些还是先前的一些老的单体应用的思想。其实无论是先前的流行微服务、还是当前的 FAAS 最重要的一个特点就是去除依赖,增强对全链路的管理功能。本身一个接口就是一个链路,链路直接如何监控、如何检查是否有循环依赖等等这才是趋势,而大型项目其实已经过时了,以后每个项目都很小,所有的小项目构成一个大的生态,基础架构慢慢沉淀变为无感知的服务。
Service 层和 Controller 层会慢慢趋向合并,如果 Service 层只为当前项目服务那就不是 Service 了,服务化最终是一个个的服务交织而成一个服务网格。
@helloyou2012 项目内分层还是很有必要的,方便维护
@helloyou2012 等年底的时候再回头看看,我预测会涌现出一批 Serverless BFF 的实现。
@zuohuadong 回复17楼的帖子
我并没有说 nest有任何不好 他有他的价值 问题是人家新开源Daruk 框架 你非要跑这下面来问 “为何不直接考虑 nest.js”? Java领域Spring 全家桶如日中天, 不还是存在Jfinal play spark的用武之地 。 而且谁会成为Node领域的 Spring还是未知数。可现在语气给人的感觉 nestjs就是 nodejs 框架的终极解决方案。非常不友好
@tao1991123 习惯了就好。
框架再好还是得看用的人~
@zuohuadong 对midway的历史这么了解,莫非你是midway的开发者之一?
@pusongyang https://www.oschina.net/news/103513/midway-1-0-released 一直比较关注midway ,多看看发布新闻
@tao1991123 我也说明了目的:希望 Daruk 在内部做好,甚至替代 yaf 。 从各家的实践来看,借鉴nest 是必然趋势。 nest 不一定是最终解决方案,目前来看是先行者,没别的意思,不要误解。 spring 也好 ror 也好,在 java,在ruby 领域的使用量都是碾压其他框架的存在。 前文中想表达的意思是,既然 java .net 的大多数开发者都对 AOP 这套思想情有独钟,并且有这十几年的沉淀,那 noder 在做后端的时候,是不是应该把这些因素考虑进去? 我只想说的是:对这个世界多一点宽容,对后端多一点敬畏。
@zuohuadong 大家说的都有道理,口味问题,不要强求。存在即合理,这几天我也好好学习一下nestjs,😄
@xiaojue 哈,期待 node.js 在新浪的发展~
关于路由的实现有一点疑问喔
在koa中,执行完上一个中间件,很自然就可以到下一个中间件了,但是在Daruk中路由和控制层合并了,即:
@get("/")
public async index(ctx: Context, next: Function) {
ctx.body = "Hello world";
}
问题:执行完index函数后,如果我还有接下来的流程需要处理,如何执行下一个函数的逻辑?
@zhulinwei Koa 的 Router 是最后一个中间件,然后就往外走了,如果你需要返回阶段处理,应该是放在前面,然后在 await next() 后面处理。可以再看看洋葱模型理解下
@atian25 刚好也有个问题,在中间件处理参数验证,中间件只能挂在router上面对吧,只有这样才能拿到routerName.
@xiaozhongliu 必然,还是上面说的,路由是最里面的一个中间件。所以你肯定要等它的路由匹配后,才能拿到你要的东西,所以需要配置为路由自身的中间件
@atian25 ok
@atian25 谢大牛提点哈哈
@zhulinwei 用next实现就行了,和中间件写法一样。