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

相关推荐
开开心心就好5 小时前
批量提取PDF中的图片,直接导出原图
前端·javascript·支持向量机·智能手机·pdf·html·启发式算法
Setsuna_F_Seiei7 小时前
前端转型 Agent 开发 05 之 Agent Hooks 与 Checkpointer(让 Agent 从全自动转变人为可掌控)
前端·agent·ai编程
百万蹄蹄向前冲9 小时前
风扇转了一晚上MVP专家团翻车事故
前端·人工智能
默_笙9 小时前
🏛 给 AI 配一间办公室:Harness Engineering 六大模块与它的实现
前端·javascript
linux_cfan10 小时前
videojs v10 源代码系列解读:14 · 谓词守卫:在运行时安全地调用能力
前端·javascript·音视频
kyriewen11 小时前
我扒了 10,221 条 JD:腾讯技术岗 75% 在要 AI
前端·人工智能·ai编程
郑州光合科技余经理11 小时前
同城外卖小程序开发:下单成功后,后台导出能不能对上用户端状态
开发语言·前端·git·后端·uni-app·php·ai编程
IT_陈寒12 小时前
Vue的响应式让我熬到凌晨三点,原来漏了这个小细节
前端·人工智能·后端
Blanche150012 小时前
利用 RAG 为答疑机器人扩展知识范围
前端
天若有情67312 小时前
【纯前端小工具】公历生日转农历,批量查询每年农历生日对应的公历日期(GitHub Pages在线直接用)
前端·javascript·github pages·农历转换·lunisolar·网页小工具