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

Zewail發表於2019-02-03

去年年初對 Node.js 比較感興趣,也用了很多 Node.js 的框架,但是開發體驗不是特別好,我之前也是後端轉前端,然後再接觸 Node.js ,所以用過挺多的服務端框架,相對js而言,設計一款服務端框架並不容易,本人也不太願意使用 typescript (為什麼不用java,請勿吐槽)編寫並且基於ES6 對入門的小夥伴會更友好一些,然後自己動手開發了一個Node.js 的Web 框架,快過年了才有時間寫文章(手動狗頭),在這裡給大家分享一下開發經歷。


注:目錄只是為了好看,想到什麼寫什麼,沒有文筆可言,小白文。


選型

對於框架底層,想過自己開發一套(成本太高,並且考慮到生態問題)被我否決了,然後比較了 Koa2 與 Express 最終選擇Koa2作為預設底層(最後由於框架的架構設計,koa2服務或者express都可以作為底層庫?),不過最後還是選擇了 koa2 預設整合。

既然選擇了 koa2 那自然也是相容 koa2 的生態圈


架構設計

剛開始開發的時候其實是順著koa的路子走的, 以koa作為底層,對koa的ctx進行擴充套件,後來覺得這樣子封裝一個koa的全家桶貌似沒什麼意義(晚上一大堆,造輪子沒什麼意義,和別的框架有啥區別,請原諒我這老土的想法?),然後開始思考?:做這個框架的初衷和意義。

作為一個後端過來的,自然就想到了用IOC容器作為底層更優雅,但是js並沒有型別約束,介面等特性,也看過很多 typescript的實現(和其他後端框架並無明顯區別,不是我吐槽,其他語言的更完善更安全效能更好),我下定決心要寫一個js(ES6)版的出來(學習成本低,更好入門?就是這麼自以為是),然後就這樣開啟了我的 Node.js 之旅。

寫偏了。。下面介紹一下這個框架的架構:

以容器作為底層,應用類整合容器基類並繫結在容器中,是應用程式物件也是容器的保姆。

其他所有的服務(包括 koa 、router、logger、validate、request、response等等)都是以提供者的形式在應用程式中註冊(實際繫結到了容器)。

容器開發

前期沒想那麼多,開發容器也很順利,在設計依賴注入模式的時候(由於沒有介面),想躲過很多方案,最後決定使用裝飾器(真香),不是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 ????????給個鼓勵~~~~

最後,祝大家新年快樂,新年新氣象 ???????


相關文章