Elpis 总结

简述

elpis 是一个沉淀了 80% 的标准性、重复性的 CRUD 工作,又提供了 20% 的个性化扩展的前端框架,能基于一份 json 配置快速搭建标准的中后台管理系统页面,同时保障稳定性与可靠性。

elpis 的整体架构如上。它是一个 BFF 层的架构,是前后端的桥梁。

  • 从一份领域模型 model 的 json 配置(如商品管理),可以拓宽到各个业务系统(如淘宝商品管理、京东商品管理)。
    • json 满足 json-shema 规范,定义前后端统一校验与数据库表设计,同时扩展出 UI 组件的配置
  • 经过 elpis BFF 的处理,可 SSR 渲染各个业务系统的首页,提升首页的渲染速度。首页内菜单系统的切换是采用的 vue-router 的 SPA,保证其流畅性。
  • 在 elpis 中,提供了常用的如 input、select等基础 UI 组件,同时支持业务方自定义组件与页面,满足业务特性需求。
  • 接口遵循 restful 规范,交互同样经过 elpis。借助洋葱圈模型思想,支持了全局错误捕获、签名校验、参数校验、日志记录等多个中间件
  • 实现不同环境的 webpack 差异化配置,满足开发与生产的不同需求

基于 koa 设计服务端引擎

为了统一代码规范,提升开发效率,借鉴 egg 的思路,设计了 elpis-core 服务端引擎

loader 自动加载

为了减少在代码中各种 require 导致的依赖不清晰,elpis 设计了约定式的目录结构,在对应目录下的文件导出的实例都会被挂在 app 对象上。具体说来,eipis 借用 glob 和 path 两个工具,将相应文件夹下的 js 文件的文件名统一改为驼峰式命名,同时实例化对象并挂载到 app 下。如 app/middleware/api-params-verify.js 中的实例最终会处理成app.middlewares.apiParamsVerify。这样可以通过 app 对象访问到任何模块,而不需要require。

rust 复制代码
app/controller/**/**.js      -->  app.controller.xxx
app/extend/**/**.js          -->  app.extend.xxx
app/middleware/**/**.js      -->  app.middleware.xxx
app/router/**/**.js          -->  app.router.xxx
app/router-schema/**/**.js   -->  app.routerSchema.xxx
app/service/**/**.js         -->  app.service.xxx
app/config/**/**.js          -->  app.config.xxx

中间件设计

利用洋葱圈模型,请求(包含业务请求和 API 请求)经过一层层的中间件过滤,再进行业务逻辑的处理,将处理后的结果再一层层返回。

elpis 中定义了三个基础中间件:

  1. 全局错误捕获。在最外层,最先使用,catch 住后续所有的错误并记录日志。再进行错误分析,如果是请求不存在的页面,则重定向到主页,不会导致页面白屏;如果是 API 请求报错,则统一返回code: 50000, message: "网络异常 请稍后重试",不会导致接口无响应。
  2. 签名校验。对接口请求,将 key 和时间戳进行 md5 加密。防止恶意请求,减少服务压力。
  3. 参数校验。从 ctx 上下文中获取接口的 body、query、header等参数并记录日志,结合 ajv + json-schema,看是否满足model/**.json中的字段定义的规则。如不满足,直接拦截。

此外,业务方可根据自己的需求定义额外的中间件。

基于 webpack 搭建前端工程化

开发环境热更新

由于首页采用 SSR 渲染,需要将模板 .tpl 文件输出到磁盘,方便后端能拿到最新的模板渲染页面。而现有的 hmr 服务如 webpack-dev-server 将所有文件保存到内存中,无法满足需求,故采用 webpack-dev-middleware 和 webpack-hot-middleware 实现定制的 hmr 服务(webpack-dev-server 就是封对二者进行了封装)。 如图,实现 hmr 服务需要两个基础能力:

  1. 监控能力。使用 webpack-dev-middleware 监控到业务文件的改变,触发解析引擎工作,将编译后的新的 js/css 文件替换掉内存中旧的。
  2. 通讯能力。使用 webpack-hot-middleware 进行通讯,通过 webSocket与浏览器保持长连接,推送文件变动事件(如 hash-changed )和新模块的加载指令(如 js/css 文件路径)。浏览器接收到通知后,从内存中动态请求新的产物文件,执行模块替换。

此外,还需进行两处配置:

  1. 由于 hmr 服务是通过 express 启动的,与后端 elpis-core 服务在不同的端口上,需要配置跨域请求允许。
  2. 客户端也需要被注入 hmr 的代码。所以需要在每个每个入口文件都加上 webpack-hot-middleware 的客户端代码,指定 HMR 的通信路径和端口。

构建与打包

不同的运行环境需要不同的配置,elpis 中一共使用了三份 webpack 文件。在 webpack.base.js 中定义了通用需配置,然后在开发环境和生产环境中通过 webpack-merge 插件的 merge.smart 引入通用配置并拓展当前环境所需的配置。

  1. 通用配置。
    • vue-loader, babel-loader , style-loader 等各种 loader 解析器
    • 别名配置(模块解析的具体行为)
    • CleanWebpackPlugin,每次build前,清空 public/dist 目录
    • 打包输出优化(代码分割,模块合并,缓存 chunkhash,压缩优化等策略)
  2. 开发环境配置。主要是 hmr。
  3. 生产环境配置。
    • 使用 thread-loader 利用多核 CPU 加快打包速度
    • 使用 mini-css-extract-plugin 抽取 css 文件,不打包到 js 中,否则会阻塞渲染。使用 css-minimizer-webpack-plugin 压缩 css
    • 使用 terser-webpack-plugin 压缩 js

总之,开发环境注重的是构建速度,生产环境注重的是文件体积大小与安全稳定性。

业务拓展

以上都是 elpis 提供的基础服务,此外 elpis 支持业务自定义工程化配置,只需要在业务对应的目录(/app/webpack.config.js)下编写 webpack 文件即可,elpis会通过 merge.smart 合并到一起。

但 elpis 不止于此,elpis 将约定优于配置发挥的淋漓尽致。除了支持业务自定义工程化配置,还支持自定义页面,自定义组件,只需在约定目录下新建文件即可。这些目录下的文件都会被合并到 elpis 中,使用 elpis 的能力。

基于 json-schema 设计动态组件体系

上文说到,elpis 支持配置化开发,用户只需要配置一份 json,即可生成一个完整的页面。如下图,这份 json,不仅仅满足 json-schema 规范,可进行数据校验,elpis 对其功能进行了扩展,可以动态设计 UI 组件。甚至,还能用于辅助数据库建表。

json-schema 规范

采用 json-schema 有以下几个原因

  • 规范完整,完全满足校验需求,且业界流行度高,有完整的校验库(ajv)支持。
  • json 只是一份数据,前端、后端、数据库可共用,避免了前后端校验不一致的情况(element-plus 中的校验只能前端使用,没法和后端保持统一)。由于定义了数据类型、是否必填等关键信息,后期数据库建表亦可参照此 json。
  • 可拓展性强。elpis 在满足 json-schema 规范的基础上拓展出了 UI 组件的描述。
css 复制代码
...
  product_name: {
    type: "string",
    label: "商品名称",
    maxLength: 10,
    minLength: 2,
    tableOption: {
      width: 200,
    },
    searchOption: {
      comType: "dynamicSelect",
      api: "/api/proj/product_name/list",
    },
    createFormOption: {
      comType: "input",
      default: "iPhone 17 pro",
    },
    editFormOption: {
      comType: "input",
    },
    detailPanelOption: {},
  },
...
  tableConfig: {
    headerButtons: [
      {
        label: "新增商品",
        eventKey: "showComponent",
        eventOption: {
          comName: "createForm",
        },
        type: "primary",
      },
    ],
    rowButtons: [
      {
        label: "详情",
        eventKey: "showComponent",
        eventOption: {
          comName: "detailPanel",
        },
        type: "primary",
        text: true,
      },
    ],
  },
  componentConfig: {
    createForm: {
      title: "新增商品",
      saveBtnText: "保存",
    },
  },
...

示例如上,对于"商品名称"这个字段,4-7 行是 json-schema 规范约束,往后都是 UI 组件描述。如在 tableOption 定义 width: 200, 则商品名称在表格中占据的宽度为200,tableOption 中的所有属性描述,可参照 eloment-plus 的 table-column,elpis 中已经做了绑定。如在 searchOption 中定义的 comType: "dynamicSelect",标识商品名称在搜索表单中的组件类型是一个动态下拉框,下拉框中的值通过 "/api/proj/product_name/list" 这个接口去获取。

动态组件设计

用户在 json 中说明字段需要在哪些地方展示(核心组件和动态组件),使用哪种组件类型(基础控件),elpis 用 Vue 的 component 标签,动态绑定 is 属性,同时给子组件传入对应的 json-schema 约束。通过 ref 收集所有子组件的引用,外层统一处理子组件的相关逻辑(如 validate 和 getValue 方法)。

  1. 基础配置

    elpis 中提供了 schema-table、schema-search-bar 两个核心组件和 createForm、editForm、detailPanel 三个动态组件 和 input、inputNumber、select、dynamicSelect、dateRange 六个基础控件。用户在 json 中可自由搭配组合,只需满足对应规范,即可配置出一个完整的 CRUD 页面。

  2. 业务拓展

    当基础配置满足不了业务需求时,elpis 支持业务拓展自己的组件。只需在约定目录下新建文件即可。具体说来:

    • 编写业务自定义组件
    • 在约定目录下创建组件映射,如 userPanel: { component: UserPanel }
    • elpis 使用 process.cwd 识别到业务约定目录下的映射文件,与自己的基础组件合并,同名会覆盖基础组件
    • Vue 的 component 标签动态渲染时,从合并后的配置对象里查找组件。无论是 elpis 内置的还是业务扩展的,都能找到

基于 docker 改造项目部署

docker

  1. 编写 DokcerFile 构建 docker 镜像,保证本地、测试、生产使用的是同一镜像,不会导致环境差异问题
  2. 镜像有tag(branch+commit),可以做版本管理,方便出现问题及时回滚

流水线

基于腾讯 DevOps 2.0-Clound Native Build(cnb)构建 CI/CD 流水线,解决以往手动拉代码、打包、上传、部署的低效问题,只需要配置一次,后续无限复用。

  1. npm run lint 检查格式化与 js 报错
  2. npm install + npm run build 打包
  3. docker build + docker push 构建 docker 镜像并推送到镜像仓库
  4. 借用 cnbcool/ssh 工具在服务器上 docker pull + docker run 启动最新镜像

后续改进

  1. 支持 typescript。现在没有类型提示,编写代码和配置容易出错;
  2. 组件联动与通信。现有组件状态无法根据其他组件状态进行动态调整,可参照 formilyjs解决该问题
  3. 可视化配置。现有配置依赖研发编写 json,对非技术人员不友好。设计一个可视化页面,支持对组件的拖拉拽和属性的更改
  4. 加上监控看板,实时查看数据。
相关推荐
麦聪聊数据14 小时前
Web 原生架构如何重塑企业级数据库协作流?
数据库·sql·低代码·架构
CSCN新手听安1 天前
【linux】网络基础(三)TCP服务端网络版本计算器的优化,Json的使用,服务器守护进程化daemon,重谈OSI七层模型
linux·服务器·网络·c++·tcp/ip·json
bloglin999991 天前
Qwen3-32B报错Invalid json output:{“type“: “1“}For troubleshooting, visit
llm·json
Trouvaille ~1 天前
【Linux】应用层协议设计实战(二):Jsoncpp序列化与完整实现
linux·运维·服务器·网络·c++·json·应用层
CORNERSTONE3651 天前
一款可提高后台系统开发效率的低代码平台
低代码·低代码平台
剩下了什么1 天前
MySQL JSON_SET() 函数
数据库·mysql·json
梦帮科技2 天前
Node.js配置生成器CLI工具开发实战
前端·人工智能·windows·前端框架·node.js·json
麦聪聊数据2 天前
为何通用堡垒机无法在数据库运维中实现精准风控?
数据库·sql·安全·低代码·架构
数据知道2 天前
PostgreSQL实战:详解如何用Python优雅地从PG中存取处理JSON
python·postgresql·json