首发于 滴滴出行小桔车服终端技术
飞马-中后台微前端页面搭建平台

飞马-中后台微前端页面搭建平台

作者我大概是只,成功的猫

引子:大家好,看到读到即是缘分。今天来给大家介绍一下团队做的中后台微前端页面搭建平台--“飞马” Peagasus,及技术实现思路。平台当前还没有对外访问的方式,在不久后会跟大家见面。欢迎联系我们相互探讨,或者加入我们“造马”的队伍。

大家使用飞马都做了什么

数据页面
数据页面
中后台系统页面
中后台系统页面

目录

适用群体



最终面向的用户群体决定了,整个平台既会提供 No Code 方式覆盖高频、UEUI 可统一化的需求场景,也会提供 Low Code 的方式覆盖无法 UIUE 统一的场景局部细节。


适用场景



关于为何要对场景进行分类,我会在下文搭建体系设计中详细阐述初衷。场景分类给我们带来的收益是用户可以更快速入手,进行具体场景下的页面搭建。


使用流程



产品背景


平台定位

做一个搭建平台,要考虑的核心问题之一便是如何用户的最终感知,换句话说便是“组件搭建粒度”。
业界的 iceluna 产品,是一个很典型的“细粒度”组件搭建平台,可以用这样抽象的语言来描述这款搭建平台,尝试把程序细节的语义或者逻辑用可视化的方式表达用以构建场景页面。
我们自己的定位如何?我们尝试不把程序化细节的语义和逻辑暴露出来,减少用户编程体验感知。做到这一点,自然要牺牲细粒度的灵活度。不过还好,对于中后台产品来说,标准化 UEUI,标准化场景组件,标准化场景页面应该是大趋势和共同的诉求。



基于以上思考,以及“希克定律”。我们决定坚定不移地将中后台系统进行“场景化”分类,标准化不同场景的 UEUI 来减少搭建细节处理。

有一个有趣的问题,我在这里抛一下,做一款“粗粒度”的搭建平台,要做的底层架构比“细粒度”搭建平台要少嘛?当然不是!我们要把底层的“细”做好后才能将“粗”抽象出来,实现后续组件生态和搭建平台的可持续发展。


平台现状


平台架构

关于飞马-中后台页面搭建系统,我门从零到一,持续输出成一个中后台搭建体系。由核心概念慢慢延展开来。





搭建平台初览






对于数据图表场景,我们会经通过绝对定位的技术方案来实现图表组件间更灵活的布局模式,以及自定义不同图表组件的大小


业务场景容器

前序

场景容器的定义

搭建平台组件与容器之间的联系

一个组件可以实现多个容器定义的规范和接口,从而可以成为一个可以用在该场景下的组件
容器(n):组件(n)


协议

场景容器协议

以 Form 容器协议为例,如何是一个标准的 Form 容器组件,换句话说组件如何被 Form 容器识别?


至少满足以下两个接口

搭建平台协议和标准

以最常见的发送 Ajax 数据请求为例,该能力被搭建平台接管,会给有需要的组件注入发送数据请求的能力


上图是具体标注方式,被标注后,该组件的对应属性“onInit”被中文化成“初始化时间”后,在搭建平台的配置面板会渲染成如下图:

组件注册扫描机制

如上架构图,详细解释了从组件开发到接入平台的流程。平台最终扫描并存储的是组件的 PropTypes 描述结构,描述结构中定义了属性的类型,一个类型对应着搭建平台配置面板的一个组件配置类型插件。


组件属性类型和搭建平台配置属性插件

这是关键的一层,该层可以近乎无限扩展来完成静态属性描述和动态代码配置之间的联系。
组件的一个属性对应着一个类型,该类型可以是基本类型,可以是复杂类型,也可以是平台可识别的预定义类型。一个类型,封装了特定的业务语义、UEUI 以及 数据结构和代码结构,比如 "api-handler" 这种预定义类型,标志着这个组件的特定属性是一个需要发送数据请求的回调接口,平台生成的代码结构最终如下:


数据通信

代码生成引擎

这也是关键的一层,后期可以做到识别不同 DSL 甚至不同语言,实现跨平台代码生成。

云端后编译

源码会随着搭建页面结构一一存储到云端,通过云端机器进行编译,最终生成页面。
根据项目流程,用户可以选择性将搭建页面发布到“开发”、“测试”或“线上”环境,达到不同环境线上页面最终产物隔离的目的。

每一次生成的线上页面,都会被记录,以备发布上线出现问题的时候快速回滚到历史的某个版本


通过 SDK 的方式接入存量中后台系统

return class extends React.Component {
  componentDidMount() {
    const innerURL = `//xmis.${
      !!envTest ? "test" : "intra"
    }.xiaojukeji.com/portal/pages/renderUrl/${page_id}?env=${env}`;
    const outerURL = `https://${
      !!envTest ? "gw-test.intra" : "gw.am"
    }.xiaojukeji.com/faas/callFn?fn=xpage&ns=xmis&env=${env}&token=${outerToken}${
      !!envTest ? "&test=true" : ""
    }`;
    const url = (page_id && innerURL) || (outerToken && outerURL); //优先page_id
    GET(url)
      .then((response) => {
        let scripts = [],
          styles = [],
          preCSS = [],
          promiseList = [];
        const data = response.data;
        data.preload_css.length &&
          data.preload_css.map((x) => preCSS.push(x.url));
        styles = [...preCSS, ...data.main_css];
        if (noCss) {
          styles = [];
        }
        styles.map((src) => {
          if (!document.getElementById(src)) {
            loadCss(src);
          }
        });
        //注意js加载顺序
        scripts = [...data.preload_js, ...data.main_js];
        scripts.map((x) => {
          if (!window[x.depNS] && !window[x.namespace]) {
            promiseList.push(
              loadJs(`pegasus-${x.depNS || x.namespace}`, x.url)
            );
          }
          if (
            (x.depNS == "axios" || x.namespace == "axios") &&
            (window[x.depNS] || window[x.namespace])
          ) {
            SetAxiosConfig(reqHeaders, withCredentials);
          }
        });
        //加载bundle.js
        if (document.getElementById("pegasus-bundle")) {
          //删除已有的bundle
          let elem = document.getElementById("pegasus-bundle");
          elem.parentNode.removeChild(elem);
        }
        promiseList.push(loadJs("pegasus-bundle", data.bundle_url));
        Promise.all(promiseList)
          .then(() => {
            console.log(
              "-----------【message from pegasus】所有前置资源加载成功 -----------"
            );
          })
          .catch((error) => {
            return new Error(error);
          });
      })
      .catch((error) => {
        let root = document.getElementById("pegasus-root");
        root.textContent = `【Pegasus资源加载失败】 ${error}`;
      });
  }
  render() {
    return <div id="pegasus-root">pegasus is loading...</div>;
  }
};


简单来说,做了两件事,
1. 加载各种页面前置资源,加载页面入口文件,植入 DOM 定位元素"pegasus-root" 。
2. 页面入口文件加载完毕后会渲染到定位元素"pegasus-root"的位置


飞马页面搭建系统 && Midway 微前端搭建系统

在日常开发中,我们也经常遇到重新建设一个中后台系统的情况,单靠飞马是无法更好地完成这类诉求。基于此类,飞马跟 Midway 微前端搭建系统携手。使用 Midway 可以快速生成一个中后台系统外壳,包含了登录、权限、菜单、顶导等一系列骨架,再使用飞马平台生成具体页面后一键集成到系统中。

总结和展望

一言道不尽技术细节,后续会分几个篇幅,更为详尽得介绍不同方向技术实现以及优劣。
页面搭建确实可以提高效率,解决开发资源与需求错配的问题。不过搭建之路最突出的矛盾,要数搭建后的页面代码如何进行二次开发?甚至如何在搭建后产物上进行更广阔的开发延展?如果真能很好解决这个问题,那么可视化搭建将进入高速路。


核心成员介绍


代做工资流水公司柳州制作背调银行流水揭阳代开企业流水打印武汉查入职流水银川代办离职证明保定打印收入证明银川银行流水电子版样本宜春薪资银行流水价格泉州贷款银行流水代办赣州房贷收入证明代办三亚打印企业贷流水青岛办理薪资流水三亚消费贷流水多少钱信阳代办消费贷流水济宁开银行流水账莆田银行流水单办理济南对公银行流水公司银川购房银行流水样本成都个人银行流水价格杭州工资银行流水开具济宁银行流水修改代办泉州银行流水账单代做潮州入职银行流水报价汕头打印签证工资流水邯郸自存流水打印赣州入职银行流水费用佛山打入职流水湛江个人流水开具唐山日常消费流水打印肇庆代开车贷银行流水广州企业流水打印香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声卫健委通报少年有偿捐血浆16次猝死汪小菲曝离婚始末何赛飞追着代拍打雅江山火三名扑火人员牺牲系谣言男子被猫抓伤后确诊“猫抓病”周杰伦一审败诉网易中国拥有亿元资产的家庭达13.3万户315晚会后胖东来又人满为患了高校汽车撞人致3死16伤 司机系学生张家界的山上“长”满了韩国人?张立群任西安交通大学校长手机成瘾是影响睡眠质量重要因素网友洛杉矶偶遇贾玲“重生之我在北大当嫡校长”单亲妈妈陷入热恋 14岁儿子报警倪萍分享减重40斤方法杨倩无缘巴黎奥运考生莫言也上北大硕士复试名单了许家印被限制高消费奥巴马现身唐宁街 黑色着装引猜测专访95后高颜值猪保姆男孩8年未见母亲被告知被遗忘七年后宇文玥被薅头发捞上岸郑州一火锅店爆改成麻辣烫店西双版纳热带植物园回应蜉蝣大爆发沉迷短剧的人就像掉进了杀猪盘当地回应沈阳致3死车祸车主疑毒驾开除党籍5年后 原水城县长再被查凯特王妃现身!外出购物视频曝光初中生遭15人围殴自卫刺伤3人判无罪事业单位女子向同事水杯投不明物质男子被流浪猫绊倒 投喂者赔24万外国人感慨凌晨的中国很安全路边卖淀粉肠阿姨主动出示声明书胖东来员工每周单休无小长假王树国卸任西安交大校长 师生送别小米汽车超级工厂正式揭幕黑马情侣提车了妈妈回应孩子在校撞护栏坠楼校方回应护栏损坏小学生课间坠楼房客欠租失踪 房东直发愁专家建议不必谈骨泥色变老人退休金被冒领16年 金额超20万西藏招商引资投资者子女可当地高考特朗普无法缴纳4.54亿美元罚金浙江一高校内汽车冲撞行人 多人受伤

代做工资流水公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化