强大的 Node.js Web 框架 - Daze.js

去年年初对 Node.js 比较感兴趣,也用了不少 Node.js 的框架,可是开发体验不是特别好,我以前也是后端转前端,而后再接触 Node.js ,因此用过挺多的服务端框架,相对js而言,设计一款服务端框架并不容易,本人也不太愿意使用 typescript (为何不用java,请勿吐槽)编写而且基于ES6 对入门的小伙伴会更友好一些,而后本身动手开发了一个Node.js 的Web 框架,快过年了才有时间写文章(手动狗头),在这里给你们分享一下开发经历。javascript


注:目录只是为了好看,想到什么写什么,没有文笔可言,小白文。前端


选型

对于框架底层,想过本身开发一套(成本过高,而且考虑到生态问题)被我否决了,而后比较了 Koa2 与 Express 最终选择Koa2做为默认底层(最后因为框架的架构设计,koa2服务或者express均可以做为底层库🤣),不过最后仍是选择了 koa2 默认集成。java

既然选择了 koa2 那天然也是兼容 koa2 的生态圈git


架构设计

刚开始开发的时候实际上是顺着koa的路子走的, 以koa做为底层,对koa的ctx进行扩展,后来以为这样子封装一个koa的全家桶貌似没什么意义(晚上一大堆,造轮子没什么意义,和别的框架有啥区别,请原谅我这老土的想法🤪),而后开始思考🤔:作这个框架的初衷和意义。github

做为一个后端过来的,天然就想到了用IOC容器做为底层更优雅,可是js并无类型约束,接口等特性,也看过不少 typescript的实现(和其余后端框架并没有明显区别,不是我吐槽,其余语言的更完善更安全性能更好),我下定决心要写一个js(ES6)版的出来(学习成本低,更好入门🤭就是这么自觉得是),而后就这样开启了个人 Node.js 之旅。web

写偏了。。下面介绍一下这个框架的架构:typescript

以容器做为底层,应用类集成容器基类并绑定在容器中,是应用程序对象也是容器的保姆。express

其余全部的服务(包括 koa 、router、logger、validate、request、response等等)都是以提供者的形式在应用程序中注册(实际绑定到了容器)。npm

容器开发

前期没想那么多,开发容器也很顺利,在设计依赖注入模式的时候(因为没有接口),想躲过不少方案,最后决定使用装饰器(真香),不是ts,使用ECMA草案中装饰器(使用 babel转码),最后1.0定稿之后,会成为可选方案,装饰器能够增长开发体验,但不是必须的,而且强烈推荐的模式进行设计。后端

例如咱们开放一个端点(路由),装饰器例子,不是注入:

@Router('users')
class UserController {
    @Get()
    index() {
        // ...
    }
}复制代码

这种模式进行开发,上述例子开放了一个 GET /users 的访问端点

那若是进行注入呢:

class UserController {
    @Config() config;
    
    @Request()
    index(request) {
        this.request.param()
        this.config.get('app.port')
    }
}复制代码

咱们能够对属性,方法,构造函数进行注入

原理是使用装饰器标记控制器属性方法等须要注入的参数,而后调用函数的时候从容器中取出(这里碰到个坑),因为http服务请求的上下文在回调函数中,因此我绑定了一个回调函数到容器中,须要获取实例的时候将上下文传入函数中,生成例如request对象的实例。


提供者

这时候开发的框架,各类服务默认绑定在容器中,与应用类耦合,虽然是框架自带的服务,可是仍是不够完美,因此借鉴了提供者的设计模式,将全部服务抽离并设计注册服务的api,在框架启动时,自动注册默认服务。


这样子,咱们的全部服务与框架底层核心彻底解耦,保证了底层核心的精简,并具备强大的可伸缩性。


模块化

既然是一个web框架,使用的时候确定会承载不一样的业务,因此咱们须要使用模块化功能拆分业务,提高可维护性,好比能够设定这个模块包含了哪几个控制器(支持通配符),这个模块须要加载哪些中间件,甚至子模块功能

因此我就设计了这么一套方案,使用模块描述类来定义模块

module.exports = class ExampleModule {
    // 标示子模块
    modules = [];
    
    // 标示须要装载的控制器
    controllers = [];

    // 标示须要加载的中间件
    middlewares = [];
}复制代码

🤓 good

请求

做为web框架,确定须要解析请求啊什么的,既然不是扩展 ctx 属性,那么个人方案就是使用 Request 类来解析 ctx, 这样的好处就是,我能够解析koactxexpressreqres或者其余框架的上下文对象,而且这个类是注册在容器中的,若是你有其余的解析方案,固然也能够本身注册一个,而后随心所欲(没错,IOC容器就是能够随心所欲😎)。

响应

生产响应的时候确定也要越方便越好,方便到你只须要在控制器中return就好,能够return各类类型,除了koa2中的支持的数据类型,还支持直接返回 框架的 View(视图,即模板)实例或者Response(响应类)实例等等,框架都会自动判断。

class UserController {
    index() {
        return [{ id: 1 }]
    }
}复制代码

就是这么方便,固然不只仅这样,还有更多强大的功能。

验证器

我在使用不少框架的时候,验证请求数据不是很方便,因此也从新设计了一套方案(狗头),

固然仍是使用装饰器模式

// 定义一个验证类,放在指定目录
class UserPostValidate extends Validate {
    @MaxLength(10) username;
    @Length(1, 20) password:
}复制代码

而后在控制器中

class UserController extends Controller {
    store() {
        this.request.validate('UserPostValidate')
    }
}
复制代码

狗头

写了很久,先去吃饭了,其实还有不少功能模块,例如日志服务、多进程服务、进程间通讯服务、安全相关服务、cookiesession服务等等,有兴趣的能够留言继续解答,或者出第二篇,下次出点技术类的~~~🐶

仓库地址: [Github]

固然,框架核心代码在 framework 这个包,目前还在开发和测试中,优化一些功能和文档,工具比较low逼,也须要完善,但愿有大牛能够一块儿开发。

目前已经到 0.8.x 版本,已经历时半年(第一个npm包提交开始),离第一个稳定版不远了!!!!正在快车道中,但愿明年尽快开放 1.0 版本服务大众。

也但愿你们能够尝试下提供各类意见反馈,因为目前就一我的开发,bug确定很多,cli工具方面已经好久没更新了,准备下一步完善工具,若是须要体验的(工具万一有bug),直接clone daze 仓库就能够。

而后,但愿你们不要吝啬本身的 star 🐶🐶🐶🐶🐶🐶🐶🐶给个鼓励~~~~

最后,祝你们新年快乐,新年新气象 🎉🎉🎉🎉🎉🎉🎉

相关文章
相关标签/搜索