elpis-core: 基于 Koa 实现 web 服务引擎架构设计解析

发布于:2025-05-14 ⋅ 阅读:(8) ⋅ 点赞:(0)

前言

内容来源于抖音【哲玄前端】大佬的《大前端全栈实践》课程,此课程是从零开始做一个企业级的全栈应用框架。此框架是基于koa.js构建的服务引擎,对BFF层的框架封装,让我感受颇深。

整体elpis项目架构设计

项目架构设计

elpis-core设计思路

 elpis-core设计思路

可以看到elpis-core是基于BFF设计理念进行开发

BFF介绍

BFF(Backend for Frontend)层,主要就是就是为了前端服务的后端。与其说是后端,不如说是各种端(Browser、APP、miniprogram)和后端各种微服务、API之间的一层胶水代码。这层代码主要的业务场景也比较集中,大多数是请求转发、数据组织、接口适配、权鉴和SSR

目录结构

├── elpis
│   ├── app                    // 文件目录
│   │   ├── controller         // 业务逻辑处理
│   │   │   ├── base.js        // 统一收拢 controller 相关的公共方法
│   │   │   ├── project.js     // 获取project数据
│   │   │   └── view.js        // 渲染页面
│   │   ├── extend             // 拓展
│   │   │   └── logger.js      // 日志工具模块
│   │   ├── middleware         // 中间件
│   │   │   ├── api-params-verify.js    // 用于验证API请求的参数是否符合规范
│   │   │   ├── api-sign-verify.js      // 签名校验中间件
│   │   │   └── error-handler.js        // 错误处理中间件(运行时异常错误处理,兜底所有异常)
│   │   ├── public             // 静态资源根目录
│   │   │   ├── output         // 页面目录
│   │   │   └── static         // 静态资源目录
│   │   ├── router             // 路由
│   │   │   ├── project.js     // project路由
│   │   │   └── view.js        // 页面路由
│   │   ├── router-schema      // 路由校验规则
│   │   │   └── project.js     // project路由规则校验
│   │   ├── service            // 数据处理
│   │   │   ├── base.js        // 统一收拢 service 相关的公共方法
│   │   │   └── project.js     // project数据处理
│   │   └── middlewares.js     // 全局中间件
│   ├── config // 环境配置文件
│   │   ├── config.beta.js     // 环境配置测试配置
│   │   ├── config.default.js  // 环境配置默认配置
│   │   ├── config.local.js    // 环境配置本地配置
│   │   └── config.prod.js     // 环境配置生产配置
│   ├── elpis-core             // 引擎内核
│   │   ├── loader
│   │   │   ├── config         // 配置区分:本地/测试/生产 通过env环境读取不同的文件配置 env.config
│   │   │   ├── controller     // 加载所有 controller 可通过 'app.controller.${目录}.${文件名}' 访问
│   │   │   ├── extend         // 加载所有 extend 可通过 'app.extend.${文件名}' 访问
│   │   │   ├── middleware     // 加载所有 middleware 可通过 'app.middleware.${目录}.${文件名}' 访问
│   │   │   ├── router-schema  // 加载所有 router-schema 可通过 'app.router-schema.${文件名}.js' 访问
│   │   │   ├── router         // 解析所有app/router下所有js文件 加载到KoaRouter下
│   │   │   └── service        // 加载所有 service 可通过 'app.service.${目录}.${文件名}' 访问
│   ├── env.js                 // 判断环境
│   └── index.js               // 启动服务的选项
└── index.js                   // 入口文件

启动服务的选项的代码

const Koa = require('koa');
const path = require('path');
const {sep} = require('path');

const env = require('./env');
const middlewareLoader = require('./loader/middleware');
const routerSchemaLoader = require('./loader/router-schema');
const routerLoader = require('./loader/router');
const controllerLoader = require('./loader/controller');
const serviceLoader = require('./loader/service');
const configLoader = require('./loader/config');
const extendLoader = require('./loader/extend');
module.exports = {
    /**
     * 启动服务
     * @param {Object} options - 启动服务的选项
     * options={
     *  name//项目名称
     *  homePage//项目首页
     * }
    */
    start(options={}) {
        // Koa 实例
        const app = new Koa();
        //应用配置
        app.options = options;
        // 基础路径
        app.baseDir = process.cwd(); // 当前工作目录
        // 业务文件路径
        app.businessPath = path.resolve(app.baseDir, `.${sep}app`);
        //判断环境
        app.env =env(app);
        console.log(`-- [start] env: ${app.env.get()} --`);
        //加载middleware
        middlewareLoader(app);
        console.log(`-- [start] load middlewareLoader done --`);
        //加载router Schema
        routerSchemaLoader(app);
        console.log(`-- [start] load routerSchemaLoader done --`);
        //加载controller
        controllerLoader(app);
        console.log(`-- [start] load controllerLoader done --`);
        //加载service
        serviceLoader(app);
        console.log(`-- [start] load serviceLoader done --`);
        //加载config
        configLoader(app);
        console.log(`-- [start] load configLoader done --`);
        //加载extend
        extendLoader(app);
        console.log(`-- [start] load extendLoader done --`);
        //注册全局中间件=>app/middleware.js
        try {
            require(`${app.businessPath}${sep}middleware.js`)(app)
            console.log('-- [start] load global middleware done -');
        } catch (error) {
            console.log('[exception] there is no middleware file .');
        }
        //注册路由
        routerLoader(app);
        console.log(`-- [start] load routerLoader done --`);
        // 启动服务
        try {
            const PORT = process.env.PORT || 8080;
            const HOST = process.env.PORT || '0.0.0.0';
            app.listen(PORT, HOST, () => {
                console.log(`Server is running at http://localhost:${PORT}`);
            }
            );
        } catch (error) {
            console.error('Error starting server:', error);
            process.exit(1);
        }
    }
}

入口文件代码

const ElpisCore= require('./elpis-core');
//启动服务
ElpisCore.start({
    name: 'elpis',
    homePage: '/'
});

通过以上目录结构以及入口代码配置,我们可以进一步总结以下几点:

  1. 模块化设计elpis-core 通过不同的 loader 模块(如 [middlewareLoader]、[routerLoader]等)实现了模块化的加载机制,使得各个功能模块(如中间件、路由、控制器等)能够按需加载并挂载到 app 实例上,便于全局使用。
  2. 环境管理:env.js文件负责环境变量的统一管理,确保在不同环境(如本地、测试、生产)下能够读取相应的配置文件,从而实现环境隔离和配置的动态切换。
  3. 业务代码组织app 目录下的代码结构清晰,遵循 elpis-core 的设计规范,将业务逻辑、数据处理、页面渲染等功能分别放在 controllerserviceview等子目录中,便于维护和扩展。
  4. 中间件机制:通过 middleware 目录下的中间件文件(如 [api-params-verify.js]、[error-handler.js]等),实现了请求参数的校验、错误处理等通用功能,增强了系统的健壮性和可维护性。
  5. 路由管理router 目录下的路由文件(如 [project.js]、[view.js] 等)与 router-schema 目录下的路由校验规则文件(如 [project.js])相结合,确保了路由的规范性和安全性。
  6. 静态资源管理public 目录用于存放静态资源(如 outputstatic),便于前端页面的渲染和资源的访问。
  7. 启动流程:入口文件 [index.js]通过调用 ElpisCore.start 方法启动服务,并传入项目名称和首页路径等配置参数,确保服务能够根据配置正确启动。

通过以上设计,elpis-core 提供了一个灵活、可扩展的框架,能够有效支持复杂业务场景的开发需求。