后端同学用 Sunamo 低代码开发前端应用是怎样的体验?

414 阅读8分钟

本文作者:xzdry

半年前,我们发布了一个低代码开源框架 Sunmao。今天我们给大家分享一下自己吃 dog food 的体验。

小 D 是公司的后端开发同学,最近接到了一个新的需求:将公司磁盘性能测试数据以可视化的形式展示出来,以便大家可以更方便的从一堆性能报告中查询某个特定的数值。

根据需求,小 D 很快找到了 Grafana 这个数据展示平台,并完成了需求:

Untitled.png

公司的同事使用后很满意,通过这个工具,能够轻松的找到需要的性能数据,这个工具为他们提供了很大的便利。

但是,随着公司业务的发展,大家很快又有了很多新需求:

  • 性能数据最好能够对比,这样能直观的看到不同版本、场景下的性能变化
  • 性能测试本身也很麻烦,能不能通过输入参数后让后端自动化运行,并在前端展示进度
  • 需要更丰富的功能,并把所有功能整合到一个前端入口

对于上面这些需求, 已经无法继续通过 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后,首先是编辑界面:

Untitled 1.png

将组件进行拖动布局,并配置参数,小 D 很快便完成了项目中的一个小需求:新建测试任务

Untitled 2.png

小 D 很满意,但是性能测试平台还需要对性能数据进行图表展示,这在 Sunmao 的组件里并没有提供。按照 Sunmao 文档的描述,需要有对应的组件开发者角色来开发这样的自定义组件。

当 Sunmao 的同学了解到这个需求后,觉得图表组件是非常通用的组件,且通过直接封装开源的ECharts 组件库可以快速的投入使用。最终决定由 Sunmao 自身维护一个 ECharts-lib 组件库:

echarts.gif

小 D 非常高兴的进行了试用,发现可以满足自己的需求,于是决定使用 Sunmao 来搭建性能测试平台的前端页面。

使用 Sunmao 的开发流程是怎样的?

小 D 通过使用 Sunmao 开发前端界面,在需求分析阶段就可以快速直观的完成一个原型,同时兼具交互性,可以很方便的向他人进行展示,并让他人实时试用,提供反馈。

在之后的设计阶段,能够以界面原型为向导,通过实际操作验证来设计后端数据库模型及要提供的API、参数类型、返回模型等。

以实现刷新作业展示 Table 为例,小 D 的开发大致分为以下阶段:

完善组件风格样式

完成原型后,小 D 就开始对其中的组件进行风格和样式的修改。以刷新按钮为例,首先通过 Button组件的 Type 属性将风格设置为 primary。之后通过 Sunmao 提供的样式编辑器来添加样式,设定宽度为 100px,最小高度为 32px:

set_button_style.gif

添加API

在小 D 的应用中,前端要展示的数据需要访问后端 RESTful API 来获取,例如刷新作业列表,就需要前端以某种方式向 /api/v1/job 接口发送 POST 请求。Sunmao 提供了非常友好的添加 / 编辑 API 的界面,可以清晰的展示 API 的参数列表,以及 Response 预览:

Untitled 3.png

通过触发这个 API,前端可以获取到要展示的作业列表和运行状态。 如果还需要添加 API 请求完成之后的处理,则可以在 onCompleteonError 中添加后续需要的逻辑。比如点击一次刷新后,需要定时自动获取最新的作业状态,就可以通过在 onComplete 中通过再次调用自身来实现轮询的效果。

添加事件

为了达到上面描述的效果,小 D 需要通过某种机制在点击刷新按钮时触发 API 调用。Sunmao 中提供了事件处理机制,仅需在组件配置的 Events 表单中进行编辑即可:

Untitled 4.png

这样,点击刷新按钮时,就会触发查询作业 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:

Untitled 5.png

上面的流程中,有一些是 Sunmao 的进阶功能,比如 JS 表达式,需要对 JS 进行一些学习。但后端出身的小 D 有着扎实的编程基础和逻辑思维能力,很快便熟悉了 JS 表达式的使用,对上述开发流程得心应手,完成了开发工作。

开发过程中遇到的问题

当然,整个开发过程并不是一帆风顺的。小 D 在搭建页面过程中也碰到了一些问题。

遍历数组动态生成组件

小 D 在开发过程中,有时候会碰到一些组件数量并不固定,需要根据参数动态生成的情况。这个操作略微复杂,所以没有写在 Sunmao 文档中。向 Sunmao 开发者求助后,小 D 得知可以使用 List 组件和特定的 Sunmao 关键字来实现效果:

List.gif

需要封装新组件

在即将完成项目时,小 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 }}
    />
  );
});

html.gif

就这样,小 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",
    )

发布后的部分效果图

Untitled 6.png

Untitled 7.png

Untitled 8.png

这样,性能测试平台 1.0 就正式完成啦。通过使用 Sunmao,小 D 成功完成了所有前端页面的搭建。并且随着使用 Sunmao 熟练度的增加,对后续版本新增的需求充满了干劲与信心!