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

相关推荐
Serendipity-Solitude20 小时前
HTML 五子棋实现方法
前端·html
frontend_frank20 小时前
脱离 Electron autoUpdater:uni-app跨端更新:Windows+Android统一实现方案
android·前端·javascript·electron·uni-app
PieroPC20 小时前
用FastAPI 一个 后端 和 两个前端 原生HTML/CSS/JS 、Vue3 写一个博客系统 例
前端·后端
wulijuan88866620 小时前
BroadcastChannel API 同源的多个标签页可以使用 BroadcastChannel 进行通讯
前端·javascript·vue.js
逝川长叹21 小时前
利用 SSI-COV 算法自动识别线状结构在环境振动下的模态参数研究(Matlab代码实现)
前端·算法·支持向量机·matlab
xkxnq21 小时前
第一阶段:Vue 基础入门(第 13天)
前端·javascript·vue.js
qq_4198540521 小时前
Excel预览
前端
PieroPc21 小时前
用FastAPI 后端 和 Vue3 前端写一个博客系统 例
前端·vue·fastapi
xiaoyustudiowww21 小时前
fetch异步简单版本(Tomcat 9)
java·前端·tomcat
TOPGUS21 小时前
谷歌Chrome浏览器即将对HTTP网站设卡:突出展示“始终使用安全连接”功能
前端·网络·chrome·http·搜索引擎·seo·数字营销