欢迎来到思维库

思维库

基于Egg.js定制业务Web框架(一) - 框架扩展

时间:2025-11-03 18:18:51 出处:IT科技阅读(143)

前言

谈到Node.js Web开发,基于你会想到的制业是什么?

首先是框架选型:Express、Koa、框架框架扩展NestJS、基于EggJS等,制业需要从繁多的框架框架扩展框架中选择一个适合团队的。 框架选好之后,基于需要初始化项目,制业安装依赖、框架框架扩展插件、基于中间件、制业配置常见库; 假如再一次做新项目,框架框架扩展还得从头初始化再来一次。基于好一点的制业可以封装一个骨架,从骨架中生成新项目,框架框架扩展周而复始。

我们先想想这样做的缺陷是什么?

如果没有骨架,团队成员技术选型不一致,变成遍地开花;每个新项目维护都有学习成本。 即便有骨架,发生一些升级也需要每个项目都统一升级一遍,后续也会导致不统一。

基于以上的原因,我们考虑的解法是服务器托管:基于通用框架封装一个统一的业务框架,将团队用到的公共功能下沉到业务框架中。

业务框架封装

框架选型

为了选择合适的底层框架,小编整理了awesome-nodejs的仓库(每个分类按github star数排序),从Web框架部分可以看到非常丰富,那么我们如何选择。

awesome-nodejs地址: https://github.com/huaize2020/awesome-nodejs/blob/main/README-zh-CN.md

主流的Web框架选型主要分为两大流派,基于Express 和 基于Koa,他们都是由同一团队打造。Express和Koa在设计思路上的区别在于:

Express本身功能内置了很多中间件,集成度高,使用省心,上手即用; Koa使用精简的内核,更轻量,使用需要使用者做技术选型按需搭建积木;

基于以上的设计思路上的差别,基于对灵活配置型的考虑,笔者选择了 基于Koa 的 流派。但他们都太底层,对于搭建企业级业务框架还需要做较多定制。

Egg.js是什么

基于上述的b2b供应网诉求,最后小编选择了Egg.js。

Egg.js地址:https://eggjs.org/zh-cn/

Egg.js是阿里开源的基于Koa2企业级Node.JS框架,其核心设计就是希望基于Egg.js孕育出更多上层框架。

引用官网的一句话

我们深知企业级应用在追求规范和共建的同时,还需要考虑如何平衡不同团队之间的差异,求同存异。所以我们没有选择社区常见框架的大集市模式(集成如数据库、模板引擎、前端框架等功能),而是专注于提供 Web 开发的核心功能和一套灵活可扩展的插件机制。「——官网」

定制目标

在开始定制业务框架前,我们先设定一下需要定制的目标。

扩展Controller,添加API成功/失败返回结果函数; 设置默认模板引擎为 pug; 扩展ctx,添加util, 将dayjs作为统一日期处理库;

编码

如果对Egg.js不太熟悉,建议可以先学习下Egg.js的基本使用。

框架初始化

通过以下命令,初始化项目。其中 --type=framework 表示框架骨架

villa-framework为框架名和项目文件夹名

$ npm init egg --type=framework villa-framework 

以下是初始化出来的目录

villa-framework ├── app │   ├── extend │   └── service ├── config │   ├── config.default.js │   └── plugin.js ├── lib │   └── framework.js ├── test │   ├── fixtures │   └── framework.test.js ├── README.md ├── index.js └── package.json 

其中app、亿华云config目录基本跟正常的Egg.js应用无差异,但增加了framework.js文件,对应用进行扩展。

// lib/framework.js use strict; const path = require(path); const egg = require(egg); const EGG_PATH = Symbol.for(egg#eggPath); class Application extends egg.Application {   get [EGG_PATH]() {     return path.dirname(__dirname);   } } class Agent extends egg.Agent {   get [EGG_PATH]() {     return path.dirname(__dirname);   } } module.exports = Object.assign(egg, {   Application,   Agent, }); 

扩展Controller,添加成功失败返回结果处理函数

// 以下是Egg.js Controller使用的代码 const Controller = require(egg).Controller; // 未来修改为 const Controller = require(villa-framework).Controller; 

由上面源码我们知道,Controller来自egg对象,因此我们只需要替换为我们定义的Controller即可。

// lib/framework.js 增加 class Controller extends egg.Controller {   ok(data) {     this.ctx.body = {       success: true,       data,     };   }   fail(message, code) {     this.ctx.body = {       code,       message,     };   } } // 导出增加Controller module.exports = Object.assign(egg, {   Application,   Agent,   Controller, }); 

这样用户使用的Controller就变成框架的Controller。

模板引擎设置为 pug

安装依赖

$ npm i --save egg-view-pug 

启动插件

// config/plugin.js exports.pug = {   enable: true,   package: egg-view-pug, }; 

设置view渲染

// config/config.default.js config.view = {   mapping: {     .pug: pug,   }, }; 

这样应用框架就不需要再单独安装配置,默认拥有pug模板引擎能力。不同的业务可以根据自己的需求,默认加载并配置一些默认插件。

扩展ctx.util, 将dayjs作为统一日期处理库

安装依赖

$ npm i --save dayjs 

app文件夹中新建util文件,添加day.js并导出

// app/util/dayjs.js use strict; const dayjs = require(dayjs); exports.dayjs = dayjs; 

因为新增的util不会默认加载,配置自定义加载器。

// config/config.default.js config.customLoader = {   // 定义在 app 上的属性名 app.util   util: {     directory: app/util,     // 如果是 ctx 则使用 loadToContext     inject: ctx,     // 是否加载框架和插件的目录     loadunit: true,   }, }; 

这样框架就会默认加载util。

应用创建

接下来我们创建应用,使用上面的villa-framework

初始化应用

$ npm init egg --type=simple villa-project $ npm i --save villa-framework $ npm i $ npm run dev 

将Egg.js上层框架修改为villa-framework

package.json中egg字段中添加 "framework": "villa-framework"

"egg": {   "framework": "villa-framework", }, 

修改controller进行测试

use strict; // app/controller/home.js const Controller = require(villa-framework).Controller; class HomeController extends Controller {   async index() {     const { dayjs } = this.ctx.util.dayjs;     const now = dayjs().format(YYYY-MM-DD HH:mm:ss);     await this.ctx.render(index.pug, { now });   }   renderOk() {     this.ok(hi, egg);   }   renderFail() {     this.fail(fail, 200);   } } module.exports = HomeController; 

添加路由

use strict; // app/router.js /**  * @param {Egg.Application} app - egg application  */ module.exports = (app) => {   const { router, controller } = app;   router.get(/, controller.home.index);   router.get(/ok, controller.home.renderOk);   router.get(/fail, controller.home.renderFail); }; 

添加首页模板

在app中创建view文件夹,并添加index.pug

html     head         title hello world     body         p hello world         p #{now} 

启动后即可看到演示的结果。

打开 http:///127.0.0.1:7001

打开 http:///127.0.0.1:7001/ok

打开 http:///127.0.0.1:7001/fail

总结

以上通过实现扩展Controller,扩展ctx,以及添加默认插件,演示了对Egg.js基本的扩展。

当然对于一个完整的业务框架,还缺少很多东西,但以上提供了一种对Egg.js的扩展的思路,希望可以为你扩展提供思路。

当前系列作为《基于Egg.js定制业务Web框架》系列一, 后续将持续输出:定制IoC容器,定制注解系统、monorepo改造、框架CLI系列,敬请关注。

框架地址:https://github.com/huaize2020/blog/tree/main/projects/villa-v1/villa-framework

应用调用地址:https://github.com/huaize2020/blog/tree/main/projects/villa-v1/villa-project

awesome-nodejs: https://github.com/huaize2020/awesome-nodejs/blob/main/README-zh-CN.md

分享到:

温馨提示:以上内容和图片整理于网络,仅供参考,希望对您有帮助!如有侵权行为请联系删除!

友情链接: