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. 加上监控看板,实时查看数据。
相关推荐
Java小卷6 小时前
流程设计器为啥选择diagram-js
前端·低代码·工作流引擎
一枚前端小姐姐2 天前
低代码平台表单设计系统技术分析(实战三)
前端·vue.js·低代码
一枚前端小姐姐2 天前
低代码平台表单设计系统技术分析(实战二)
低代码·架构·前端框架
一枚前端小姐姐2 天前
低代码平台表单设计系统架构分析(实战一)
前端·低代码·架构
麦聪聊数据3 天前
统一 Web SQL 平台如何收编企业内部的“野生数据看板”?
数据库·sql·低代码·微服务·架构
上海合宙LuatOS4 天前
LuatOS核心库API——【json 】json 生成和解析库
java·前端·网络·单片机·嵌入式硬件·物联网·json
敲代码的柯基4 天前
一篇文章理解tsconfig.json和vue.config.js
javascript·vue.js·json
canonical_entropy4 天前
当复杂性被显式化:Nop平台的认知经济学
后端·低代码·aigc
麦聪聊数据4 天前
数据流通的最后一公里:SQL2API 在企业数据市场中的履约架构实践
数据库·sql·低代码·微服务·架构