本文作者:xzdry
半年前,我们发布了一个低代码开源框架 Sunmao。今天我们给大家分享一下自己吃 dog food 的体验。
小 D 是公司的后端开发同学,最近接到了一个新的需求:将公司磁盘性能测试数据以可视化的形式展示出来,以便大家可以更方便的从一堆性能报告中查询某个特定的数值。
根据需求,小 D 很快找到了 Grafana 这个数据展示平台,并完成了需求:
公司的同事使用后很满意,通过这个工具,能够轻松的找到需要的性能数据,这个工具为他们提供了很大的便利。
但是,随着公司业务的发展,大家很快又有了很多新需求:
- 性能数据最好能够对比,这样能直观的看到不同版本、场景下的性能变化
- 性能测试本身也很麻烦,能不能通过输入参数后让后端自动化运行,并在前端展示进度
- 需要更丰富的功能,并把所有功能整合到一个前端入口
- …
对于上面这些需求, 已经无法继续通过 Grafana 完成了。
为什么选择 Sunmao?
经过对需求进行分析,小 D 发现自己需要的实际是一个前端 Web 平台。但此时公司前端同学暂时没有人力,自己从头开始学习前端知识进行开发又非常耗费时间。
经过查找资料,小 D 了解到了近年来非常火热的低代码平台。比如 Retool、Appsmith 等。小 D 进行了简单的调研,发现 Retool 虽然很强大,但却是闭源,一些功能比如发布应用需要购买升级计划。 Appsmith 虽然开源,但组件风格不太符合整体项目需求,且随着业务的复杂化,组件的拓展能力可能会不足…
恰好此时小 D 了解到公司刚发布了开源的低代码工具 Sunmao,通过和 Sunmao 的开发同学交流后,小 D 了解到 Sunmao 提供了完整的前端 Web UI 支持,同时提供了基于 Arco Design 封装的 Arco-lib 组件库,有丰富的 UI 组件可以使用。并且在组件的整体风格上,十分贴合项目的需求。
于是小 D 在 Sunmao 官网提供的 Playground 上进行了简单的试用,打开Sunmao Editor后,首先是编辑界面:
将组件进行拖动布局,并配置参数,小 D 很快便完成了项目中的一个小需求:新建测试任务
小 D 很满意,但是性能测试平台还需要对性能数据进行图表展示,这在 Sunmao 的组件里并没有提供。按照 Sunmao 文档的描述,需要有对应的组件开发者角色来开发这样的自定义组件。
当 Sunmao 的同学了解到这个需求后,觉得图表组件是非常通用的组件,且通过直接封装开源的ECharts 组件库可以快速的投入使用。最终决定由 Sunmao 自身维护一个 ECharts-lib 组件库:
小 D 非常高兴的进行了试用,发现可以满足自己的需求,于是决定使用 Sunmao 来搭建性能测试平台的前端页面。
使用 Sunmao 的开发流程是怎样的?
小 D 通过使用 Sunmao 开发前端界面,在需求分析阶段就可以快速直观的完成一个原型,同时兼具交互性,可以很方便的向他人进行展示,并让他人实时试用,提供反馈。
在之后的设计阶段,能够以界面原型为向导,通过实际操作验证来设计后端数据库模型及要提供的API、参数类型、返回模型等。
以实现刷新作业展示 Table 为例,小 D 的开发大致分为以下阶段:
完善组件风格样式
完成原型后,小 D 就开始对其中的组件进行风格和样式的修改。以刷新按钮为例,首先通过 Button
组件的 Type 属性将风格设置为 primary
。之后通过 Sunmao 提供的样式编辑器来添加样式,设定宽度为 100px,最小高度为 32px:
添加API
在小 D 的应用中,前端要展示的数据需要访问后端 RESTful API 来获取,例如刷新作业列表,就需要前端以某种方式向 /api/v1/job
接口发送 POST 请求。Sunmao 提供了非常友好的添加 / 编辑 API 的界面,可以清晰的展示 API 的参数列表,以及 Response 预览:
通过触发这个 API,前端可以获取到要展示的作业列表和运行状态。 如果还需要添加 API 请求完成之后的处理,则可以在 onComplete
和 onError
中添加后续需要的逻辑。比如点击一次刷新后,需要定时自动获取最新的作业状态,就可以通过在 onComplete 中通过再次调用自身来实现轮询的效果。
添加事件
为了达到上面描述的效果,小 D 需要通过某种机制在点击刷新按钮时触发 API 调用。Sunmao 中提供了事件处理机制,仅需在组件配置的 Events 表单中进行编辑即可:
这样,点击刷新按钮时,就会触发查询作业 API,获得作业的最新运行状态。 其他的响应事件,例如弹出窗口,列表翻页等场景,也可以通过同样的方式完成。
数据的转换与展示
小 D 将后端提供的各个 API 都通过 Sunmao 添加到了前端,通过这些 API,他可以轻松获取要展示的数据,但这些数据并不能直接被前端组件使用,这时候就需要添加一些转换逻辑对数据的格式进行转换。Sunmao 中提供了完整的 JS 表达式支持,通过使用 JS 表达式,这项工作可以轻松完成。 比如,要转换查询作业 API 返回的数据,就可以通过一个立即执行函数来处理:
{{
(function(){
const jobs = [];
let i = 0;
for (const job of (get_joblist.fetch.data?.data[1] || [])) {
const stime = new Date(job.stime * 1000);
const etime = new Date(job.etime * 1000);
const time_left = 0;
// 转换逻辑...
jobs.push({
"key": job.jobid,
"index": i,
"jobname": job.jobname,
"type": job.type,
"status": job.status,
"progress": job.progress.toFixed(2),
"stime": job.stime == 0 ? "-" : stime.toLocaleString(),
"etime": job.etime == 0 ? "-" : etime.toLocaleString(),
});
i += 1;
}
return jobs;
})()
}}
将写好的表达式作为 Table Data 属性的输入,就完成了作业展示 Table:
上面的流程中,有一些是 Sunmao 的进阶功能,比如 JS 表达式,需要对 JS 进行一些学习。但后端出身的小 D 有着扎实的编程基础和逻辑思维能力,很快便熟悉了 JS 表达式的使用,对上述开发流程得心应手,完成了开发工作。
开发过程中遇到的问题
当然,整个开发过程并不是一帆风顺的。小 D 在搭建页面过程中也碰到了一些问题。
遍历数组动态生成组件
小 D 在开发过程中,有时候会碰到一些组件数量并不固定,需要根据参数动态生成的情况。这个操作略微复杂,所以没有写在 Sunmao 文档中。向 Sunmao 开发者求助后,小 D 得知可以使用 List
组件和特定的 Sunmao 关键字来实现效果:
需要封装新组件
在即将完成项目时,小 D 想加入一份 License 条款。这份条款是公司的前端部门预先提供的,内容包含了很多 HTML 标签,比如加粗、链接、高亮标题等等。这时候就需要一个能支持插入 HTML 内容的组件。但这不是一个通用的需求,Sunmao 没有提供这样的组件。不过 Sunmao 提供了十分方便的组件封装方法,而且组件本身也很简单。所以经过阅读 Sunmao 开发文档,小 D 最终自己完成了 HTML 组件的封装。
import { implementRuntimeComponent } from '@sunmao-ui/runtime';
import { Type } from '@sinclair/typebox';
import { css } from '@emotion/css';
export default implementRuntimeComponent({
version: 'custom/v1',
metadata: {
name: 'license',
displayName: 'License',
description: '',
exampleProperties: {
html: '',
},
annotations: {
category: 'Display',
},
},
spec: {
properties: Type.Object({
html: Type.String(),
}),
state: Type.Object({}),
methods: {},
slots: {},
styleSlots: ['content'],
events: [],
},
})(({ elementRef, customStyle, html }) => {
return (
<div
ref={elementRef}
className={css(customStyle?.content)}
dangerouslySetInnerHTML={{ __html: html }}
/>
);
});
就这样,小 D 也体验了一番前端开发的快乐~
打包与发布
开发完成后,Sunmao 的产出仅有一些 JSON 文件,这些文件中保存了应用的所有信息。小 D 可以十分方便的存储和移动。在任何项目中,只要 import
了 Sunmao Runtime ,就都可以加载这些 JSON 来运行。
发布时,Sunmao 的编译也十分简单,就像打包一个常规的前端项目一样。最终产物就是 HTML 和 JS 文件。
之后小 D 只需要通过自己使用的 FastAPI 框架提供的 mount 功能,把静态文件挂载到后端 Server 中就可以随着后端应用一起发布:
@app.on_event("startup")
async def start_app():
static_www_root = os.getenv("WWW_PATH")
app.mount(
"/",
StaticFiles(directory=static_www_root, html=True),
name="static",
)
发布后的部分效果图
这样,性能测试平台 1.0 就正式完成啦。通过使用 Sunmao,小 D 成功完成了所有前端页面的搭建。并且随着使用 Sunmao 熟练度的增加,对后续版本新增的需求充满了干劲与信心!