elpis-core: 基于 Koa 实现 web 服务引擎架构设计解析
前言
内容来源于抖音【哲玄前端】大佬的《大前端全栈实践》课程,此课程是从零开始做一个企业级的全栈应用框架。此框架是基于koa.js构建的服务引擎,对BFF层的框架封装,让我感受颇深。
整体elpis项目架构设计
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()} --`);//加载middlewaremiddlewareLoader(app);console.log(`-- [start] load middlewareLoader done --`);//加载router SchemarouterSchemaLoader(app);console.log(`-- [start] load routerSchemaLoader done --`);//加载controllercontrollerLoader(app);console.log(`-- [start] load controllerLoader done --`);//加载serviceserviceLoader(app);console.log(`-- [start] load serviceLoader done --`);//加载configconfigLoader(app);console.log(`-- [start] load configLoader done --`);//加载extendextendLoader(app);console.log(`-- [start] load extendLoader done --`);//注册全局中间件=>app/middleware.jstry {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: '/'
});
通过以上目录结构以及入口代码配置,我们可以进一步总结以下几点:
- 模块化设计:
elpis-core
通过不同的loader
模块(如 [middlewareLoader]、[routerLoader]等)实现了模块化的加载机制,使得各个功能模块(如中间件、路由、控制器等)能够按需加载并挂载到app
实例上,便于全局使用。 - 环境管理:env.js文件负责环境变量的统一管理,确保在不同环境(如本地、测试、生产)下能够读取相应的配置文件,从而实现环境隔离和配置的动态切换。
- 业务代码组织:
app
目录下的代码结构清晰,遵循elpis-core
的设计规范,将业务逻辑、数据处理、页面渲染等功能分别放在controller
、service
、view
等子目录中,便于维护和扩展。 - 中间件机制:通过
middleware
目录下的中间件文件(如 [api-params-verify.js]、[error-handler.js]等),实现了请求参数的校验、错误处理等通用功能,增强了系统的健壮性和可维护性。 - 路由管理:
router
目录下的路由文件(如 [project.js]、[view.js] 等)与router-schema
目录下的路由校验规则文件(如 [project.js])相结合,确保了路由的规范性和安全性。 - 静态资源管理:
public
目录用于存放静态资源(如output
、static
),便于前端页面的渲染和资源的访问。 - 启动流程:入口文件 [index.js]通过调用
ElpisCore.start
方法启动服务,并传入项目名称和首页路径等配置参数,确保服务能够根据配置正确启动。
通过以上设计,
elpis-core
提供了一个灵活、可扩展的框架,能够有效支持复杂业务场景的开发需求。