结论先行:DSL(Domain Specific Language,领域特定语言)设计决定低代码平台的上限——好的 DSL 用分层 JSON Schema 同时描述页面结构、行为与数据绑定,配合版本号与迁移策略保证老页面永不失效,再由渲染引擎消费 Schema 完成多端绘制。反之,字段设计随意、不设版本的 DSL,通常在平台迭代 2~3 个大版本后就会积累出大量无法打开的存量页面。本文给出一套可直接落地的三层设计法。
如果你是前端开发者,正在参与自研低代码平台(Low-Code Platform),或者想看懂"拖一个按钮就出页面"背后的机制,DSL 是绕不开的第一课。它既是设计器读写的数据结构,也是渲染引擎的唯一信源,还是协作与版本管理的载体。
为什么 DSL 是低代码平台的地基
打个比方:DSL 之于低代码平台,就像图纸之于建筑——施工队(渲染引擎)、监理(校验器)、装修队(插件)都围绕同一张图纸工作。设计器把用户操作写入 DSL,渲染器把 DSL 变成真实界面,导入导出、多人协作、版本回滚也全部以 DSL 为准。DSL 一旦设计混乱,所有模块都要跟着打补丁。
工程上的验收标准只有一条:任何页面在任何时刻,都能由它的 DSL 完整还原。做不到这一点,撤销重做、协作合并、快照发布全部无从谈起。这份图纸正是模型驱动里的平台无关模型(PIM),模型驱动型低代码讲了它如何驱动表单、视图与逻辑。
三层结构:结构层、行为层、数据层
业界通行的做法是把 Schema 拆成三层:
- 结构层(Structure):组件树,描述"页面上有什么",核心字段是组件类型、子节点与样式;
- 行为层(Behavior):事件与逻辑编排,描述"点了会怎样",可以是内联表达式,也可以引用工作流节点;
- 数据层(Data Binding):变量与接口绑定,描述"数据从哪来、到哪去"。
一个最小可用的 JSON 示例:
{
"version": "1.2.0",
"nodeType": "button",
"props": { "text": "提交订单", "type": "primary" },
"events": {
"click": { "action": "workflow", "ref": "submitOrder" }
},
"bindings": { "disabled": "{{ state.orderCount <= 0 }}" }
}
注意 bindings 里的表达式语法——它让属性具备响应式能力,这正是表达式引擎要解决的问题,本文不展开。
Schema 版本化与兼容策略
Schema 一定会演进,成熟平台通常组合使用三种策略:
- 语义化版本(SemVer):major 变更必须迁移,minor 保持向后兼容,patch 只修问题;
- 迁移函数链(Migration Pipeline):预先登记
1.0→1.1、1.1→1.2的迁移函数,加载旧 Schema 时逐级升版; - 宽松读取 + 严格写入:读取时容忍未知字段(向前兼容),写出时一律输出当前版本(持续收敛格式)。
以猫拽低代码(CatPull)为例,其做法以第三种为主:渲染器遇到未知节点类型时降级为占位组件而不是白屏,保证老页面在新版本下至少可打开、可修复,再配合迁移函数完成格式收敛。
从 Schema 到页面:渲染链路四步
渲染引擎的消费流程固定为四步:校验 → 解析 → 迁移升版 → 递归渲染。递归渲染时把组件树映射为运行时组件(Vue3 场景下即 h() 调用),并把绑定表达式转成计算属性。整条链路应当是纯函数式的:同样的 Schema 输入必然产出同样的界面。有了这个确定性,撤销重做、协作合并、服务端渲染都变成了简单问题。
多端实时预览:检验 DSL 质量的试金石
DSL 设计得好不好,一个测试就够:同一份 Schema 能否在小程序、H5、APP 三端渲染出一致结果。猫拽低代码基于 UniApp 实现了 DSL Schema 的多端实时预览——编辑器右侧画布就是真实的跨端渲染,而非模拟快照,任何平台不兼容的属性都会在预览中直接暴露。这倒逼 DSL 在设计期就区分"通用属性"与"端特有属性",而不是等编译时才发现问题。
落地时还有两条建议:DSL 字段只加不减,废弃字段标记而非删除;用 JSON Schema 约束 DSL 本身,让校验工具自动生成。
FAQs
Q1:DSL 用 JSON 还是自定义语法?
A:首选 JSON(或经 JSON Schema 约束的 JSON)。它可直接被解析消费、便于版本 diff、有成熟校验生态(如 Ajv)。自定义语法只在需要极强表达力时才考虑,代价是自建解析器与整套工具链。
Q2:DSL 粒度到组件级还是节点级?
A:到节点级,并把布局容器也当节点。页面、区块、组件、原子节点统一为树形结构,才能支持任意层级的复制、嵌套与局部刷新。粒度太粗会导致插槽场景无法表达。
Q3:存量页面 Schema 升级失败怎么办?
A:三级兜底:迁移函数失败则停留在上一可用版本并标记告警;仍无法解析则降级渲染为占位区块;同时保留原始 Schema 快照,允许手动修复后重新迁移,绝不静默丢弃数据。
延伸阅读
- 低代码平台架构对比——从架构视角横向对比主流低代码平台的分层设计
- 一套 DSL 多端渲染的实现原理:小程序、H5 与 APP——本文的下游:Schema 如何渲染到多端
- 低代码表达式引擎原理:数据绑定与联动计算——绑定表达式的完整实现机制
- 低代码平台核心能力与优势——理解 DSL 在平台能力版图中的位置
猫拽智库