学习 elpis 有感 -- 初识 elpis-core (实现简易版 Egg.js)

首先什么是 Egg.js ?

Egg.js 是 阿里 开源的 Node.js 企业级应用框架 ,基于 Koa 封装,提供更强的规范性和扩展性。它的核心理念是 "约定大于配置"(Convention Over Configuration) ,即通过 "预设规则" 减少开发者的决策成本,提升团队协作效率。

为什么要用约定 ?

核心原因分为两种:1. 开发习惯差异 2. 人员更迭风险

我们假设一个场景,开发者A可能将用户模块的数据库操作写在Controller里(MVC习惯),开发者B却独立出Domain Service层(DDD习惯)。比如项目组有10人,开发习惯五花八门。有一天B离职了工作需要A接手,A不得不花费大量时间理解这些个性化风格;再假设项目干上2-3年,恐怕会慢慢变成一个烫手的山芋...没人愿意接手这个烂摊子。于是 "约定大于配置" 的理念诞生了,Egg.js 强制约定 controller 只处理HTTP请求、service 承载业务逻辑... 使得新人加入时能立即定位代码。

elpis-core 登场

elpis-core 是参考 Egg.js "约定大于配置" 理念实现的服务端框架。

核心分为以下7个模块:

  • middleware(中间件)
  • config(配置项)
  • router(路由)
  • router-schema(路由参数校验规范)
  • controller(控制器)
  • service(服务)
  • extend(扩展例如日志)

接下来我用 middleware.js 举例说明 elpis-core 内核内部运作的原理。

ini 复制代码
module.exports = (app) => {
    // 读取 app/middleware/**/**.js 下所有的文件
    const middlewarePath = path.resolve(app.businessPath, `.${sep}middleware`);
    const fileList = glob.sync(path.resolve(middlewarePath, `.${sep}**${sep}**.js`));

    // 遍历所有文件目录,把内容加载到 app.middlewares 下
    const middlewares = {};
    fileList.forEach((file) => {
        // 提取文件名称
        let name = path.resolve(file);

        // 截取路径 app/middleware/custom-module/custom-middleware.js => custom-module/custom-middleware
        name = name.substring(name.lastIndexOf(`middleware${sep}`) + `middleware${sep}`.length, name.lastIndexOf("."));

        // 把 '-' 统一改为驼峰式,custom-module/custom-middleware => customModule.customMiddleware
        name = name.replace(/[_-][a-z]/gi, (s) => s.substring(1).toUpperCase());

        // 挂载 middleware 到内存 app 对象中
        let tempMiddleware = middlewares;
        const names = name.split(sep);
        for (let i = 0, len = names.length; i < len; ++i) {
            if (i === len - 1) {
                // 文件
                tempMiddleware[names[i]] = require(path.resolve(file))(app);
            } else {
                // 文件夹
                if (!tempMiddleware[names[i]]) {
                    tempMiddleware[names[i]] = {};
                }
                tempMiddleware = tempMiddleware[names[i]];
            }
        }
    });
    app.middlewares = middlewares;
};

这段代码实现了一个 自动加载中间件 的机制,它会扫描 app/middleware/ 目录下的所有 .js 文件,并按一定的规则挂载到 app.middlewares 对象上,方便在项目中统一调用。

例如我创建了文件: app/middleware/api-params-verify.js ,那么我可以在任何地方 app.middlewares.apiParamsVerify 使用它。再或者我们进行业务开发时定义了一个 service app/service/project.js 那么我们可以直接在controller中这样去调用 project 的 getList 方法。

ini 复制代码
const { project: projectService } = app.service;
const projectList = projectService.getList();

其余模块的原理也类似,在此不做过多代码说明。

结语

elpis-core 它就像是一个乐高说明书,虽然限制了拼装方式,但能保证所有人拼出来的都是稳固结构,特别适合需要长期维护的企业级应用。

相关推荐
qetfw11 分钟前
MXU:Tauri 2 + React 的 MaaFramework 跨平台 GUI 源码
前端·python·react.js·前端框架·开源项目·效率工具
甲维斯12 分钟前
我要开始吹牛逼了!Kimi K3 “宇宙无敌”!
前端·人工智能
a11177619 分钟前
微光小屋-前端养成小游戏 开源项目
前端
kyriewen32 分钟前
我让AI给前端项目做了一次完整的Code Review——它和人类的差距,比我想的大得多
前端·javascript·ai编程
张鑫旭32 分钟前
快速过下我2026年上半年的前端学了些啥
前端
এ慕ོ冬℘゜1 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript
hoLzwEge1 小时前
拯救低效调试!code-inspector-plugin 让代码定位如虎添翼
前端·前端框架·node.js
J船长1 小时前
烂笔头扫盲:LLM Eval 入门:从「感觉挺好」到「数据说话」的工程化落地
前端
skiyee2 小时前
被多个 UView 系 UI 库 “抄” 的 @uni-ku/root 究竟怎么实现?
前端