低代码平台架构设计方案 - 从浅入深完整指南(4-3)
前言: 本文系统阐述了一套完整的低代码平台架构设计方案,涵盖从基础架构到企业级应用的全链路技术实现。
核心内容:
🏗️ 四层架构体系:可视化设计器、Schema协议、运行时引擎、物料体系的完整设计
🔄 全局状态管理:基于Zustand的页面级Store架构,支持跨组件数据流动
⚡ 性能优化方案:三种发布模式(纯运行时、Schema编译、混合模式)对比与实践
🎯 动作系统:枚举化业务操作设计,实现配置化与安全性的平衡
🔧 Schema编译器:深度解析编译优化策略,在保持Runtime架构一致性的同时实现70%体积优化
🚀 SSR支持:Next.js集成方案,满足SEO与首屏性能需求
📦 发布流程:从Schema保存到产物部署的完整工程化实践
适合人群:前端架构师、低代码平台开发者、对前端工程化感兴趣的技术人员
全文15万+字,涵盖架构设计、核心实现、性能优化、工程实践等多个维度,提供可直接落地的技术方案。
5.10 渲染器集成:状态注入与事件收集
关键步骤:
- 创建全局 Runtime (包含 GlobalStore)
- 遍历组件树,解析表达式注入状态
- 收集事件配置,转换为真实的事件处理函数
- 订阅 Store 变化,实现响应式更新
// renderer/Renderer.jsx
import React, { useState, useEffect, useSyncExternalStore } from 'react';
import MaterialRegistry from '../material-registry/MaterialRegistry';
import LowCodeRuntime from '../runtime/LowCodeRuntime';
/**
* 低代码渲染器
*
* 职责:
* 1. 初始化全局 Runtime (包含 GlobalStore、Methods 等)
* 2. 递归渲染组件树
* 3. 解析表达式 (如 ${store.users}) 并注入到 props
* 4. 收集 events 配置并转换为事件处理函数
* 5. 订阅 Store 变化,触发重新渲染
*/
function Renderer({ schema }) {
// 创建全局 Runtime 实例 (整个页面只有一个)
const [runtime] = useState(() => {
console.log('🚀 初始化 Runtime with schema.store:', schema.store);
return new LowCodeRuntime(schema);
});
// 订阅全局 Store 的变化
// 当 Store 更新时,会触发所有使用该状态的组件重新渲染
const store = useSyncExternalStore(
runtime.store.subscribe.bind(runtime.store),
() => runtime.store.getStore()
);
useEffect(() => {
console.log('✅ Runtime mounted, store:', store);
return () => {
console.log('❌ Runtime unmounting');
runtime.destroy();
};
}, []);
/**
* 递归渲染节点
*
* @param {Object} nodeSchema - 节点配置
* @returns {ReactElement}
*/
const renderNode = (nodeSchema) => {
const { id, componentName, props = {}, children, events } = nodeSchema;
// 1️⃣ 从物料注册表获取组件
const Component = MaterialRegistry.getComponent(componentName);
if (!Component) {
console.warn(`❌ Component ${componentName} not found`);
return null;
}
// 2️⃣ 解析 props 中的表达式,注入全局状态
// 例如: { users: "${store.users}" }
// → { users: [实际的用户数组] }
const resolvedProps = resolvePropsWithExpressions(props, runtime);
// 3️⃣ 收集并转换 events 配置为真实的事件处理函数
// 例如: { onClick: { type: "callMethod", payload: {...} } }
// → { onClick: async () => { runtime.callMethod(...) } }
const eventHandlers = collectEventHandlers(id, events, runtime);
// 4️⃣ 递归渲染子节点
const childNodes = children?.map((child, index) =>
renderNode({ ...child, id: child.id || `${id}_child_${index}` })
);
// 5️⃣ 使用 React.createElement 创建真实的 React 元素
return React.createElement(
Component,
{
key: id,
...resolvedProps, // 注入状态
...eventHandlers // 注入事件处理器
},
childNodes
);
};
return (
<div className="lowcode-renderer">
{renderNode(schema.componentTree)}
</div>
);
}
/**
* 解析 props 中的表达式
*
* @param {Object} props - 原始 props 配置
* @param {LowCodeRuntime} runtime - 运行时实例
* @returns {Object} 解析后的 props
*/
function resolvePropsWithExpressions(props, runtime) {
const resolved = {};
for (const [key, value] of Object.entries(props)) {
if (typeof value === 'string' && value.includes('${')) {
// 表达式: "${store.users}" → [实际数据]
resolved[key] = runtime.expression.evaluate(value);
console.log(`📊 表达式解析: ${key}:`, {
原始值: value,
解析结果: resolved[key]
});
} else if (typeof value === 'object' && value !== null) {
// 递归解析嵌套对象
resolved[key] = resolvePropsWithExpressions(value, runtime);
} else {
// 普通值直接传递
resolved[key] = value;
}
}
return resolved;
}
/**
* 收集事件配置并转换为事件处理函数
*
* @param {string} nodeId - 节点ID
* @param {Object} events - 事件配置
* @param {LowCodeRuntime} runtime - 运行时实例
* @returns {Object} 事件处理器映射
*/
function collectEventHandlers(nodeId, events, runtime) {
if (!events) return {};
const handlers = {};
for (const [eventName, eventConfig] of Object.entries(events)) {
// 创建事件处理函数
// 当组件调用 props.onClick(...args) 时,会执行这个函数
handlers[eventName] = runtime.eventSystem.createEventHandler(
nodeId,
eventName,
eventConfig
);
console.log(`🎯 事件注册: ${eventName}`, {
组件ID: nodeId,
事件配置: eventConfig
});
}
return handlers;
}
export default Renderer;
完整的渲染流程示意图:
Schema 定义
├── store: { users: [] }
├── methods: { handleDelete: {...} }
└── componentTree: { ... }
↓
┌────────────────────────────────────────────────────┐
│ 1. 初始化 Runtime │
│ - 创建 GlobalStore (Zustand) │
│ - 注册全局 Methods │
│ - 初始化 EventSystem、ExpressionEngine │
└──────────────┬─────────────────────────────────────┘
↓
┌────────────────────────────────────────────────────┐
│ 2. 递归渲染组件树 │
│ - 获取组件: MaterialRegistry.get('UserList') │
│ - 解析表达式: "${store.users}" → [数组] │
│ - 收集事件: { onDelete: {...} } → 函数 │
└──────────────┬─────────────────────────────────────┘
↓
┌────────────────────────────────────────────────────┐
│ 3. 创建 React 元素 │
│ React.createElement( │
│ UserList, │
│ { │
│ users: [实际数组], ← 来自 GlobalStore │
│ onDelete: async (id) => { ← 事件处理器 │
│ await runtime.callMethod('handleDelete') │
│ } │
│ } │
│ ) │
└──────────────┬─────────────────────────────────────┘
↓
渲染真实的 React 组件
↓
用户交互 (点击删除)
↓
触发 onDelete(userId)
↓
执行全局 Method
↓
更新 GlobalStore
↓
所有依赖该状态的组件自动重新渲染
5.11 完整案例:用户管理页面
这个案例展示了如何使用全局 Store、全局 Methods、数据源和事件系统构建一个完整的 CRUD 页面。
{
"version": "1.0.0",
// 全局状态 Store
"store": {
"users": [],
"modalVisible": false,
"selectedUser": null,
"filters": {
"keyword": "",
"status": "all"
}
},
// 数据源定义
"dataSources": [
{
"id": "userList",
"type": "http",
"config": {
"url": "/api/users",
"method": "GET",
"autoLoad": true
}
}
],
// 页面生命周期
"lifeCycles": {
"onMount": [
{ "type": "setStore", "payload": { "loading": true } },
{ "type": "fetchDataSource", "payload": { "id": "userList" } }
]
},
// 全局方法
"methods": {
"handleDelete": {
"params": ["userId"],
"actions": [
{ "type": "confirm", "payload": { "message": "确认删除?" } },
{
"type": "request",
"payload": {
"url": "/api/users/${params[0]}",
"method": "DELETE"
}
},
{ "type": "message", "payload": { "type": "success", "content": "删除成功" } },
{ "type": "fetchDataSource", "payload": { "id": "userList" } }
]
},
"handleEdit": {
"params": ["user"],
"actions": [
{
"type": "setStore",
"payload": {
"selectedUser": "${params[0]}",
"modalVisible": true
}
}
]
},
"handleModalClose": {
"actions": [
{
"type": "setStore",
"payload": {
"modalVisible": false,
"selectedUser": null
}
}
]
},
"handleFilterChange": {
"params": ["filters"],
"actions": [
{ "type": "setStore", "payload": { "filters": "${params[0]}" } },
{ "type": "fetchDataSource", "payload": { "id": "userList" } }
]
}
},
// 组件树
"componentTree": {
"componentName": "Page",
"props": { "title": "用户管理" },
"children": [
// 操作栏
{
"componentName": "Space",
"props": { "style": { "marginBottom": 16 } },
"children": [
{
"componentName": "Button",
"props": {
"type": "primary",
"children": "新增用户"
},
"events": {
"onClick": {
"type": "setStore",
"payload": { "selectedUser": null, "modalVisible": true }
}
}
},
{
"componentName": "Input",
"props": {
"placeholder": "搜索用户",
"value": "${store.filters.keyword}"
},
"events": {
"onChange": {
"type": "callMethod",
"payload": {
"method": "handleFilterChange",
"params": ["${Object.assign({}, store.filters, { keyword: event.target.value })}"]
}
}
}
}
]
},
// 用户表格
{
"componentName": "Table",
"props": {
"dataSource": "${dataSource.userList.data}",
"loading": "${dataSource.userList.loading}",
"rowKey": "id",
"columns": [
{ "title": "用户名", "dataIndex": "username" },
{ "title": "邮箱", "dataIndex": "email" },
{ "title": "状态", "dataIndex": "status" },
{
"title": "操作",
"render": {
"componentName": "Space",
"children": [
{
"componentName": "Button",
"props": {
"type": "link",
"children": "编辑"
},
"events": {
"onClick": {
"type": "callMethod",
"payload": {
"method": "handleEdit",
"params": ["${record}"]
}
}
}
},
{
"componentName": "Button",
"props": {
"type": "link",
"danger": true,
"children": "删除"
},
"events": {
"onClick": {
"type": "callMethod",
"payload": {
"method": "handleDelete",
"params": ["${record.id}"]
}
}
}
}
]
}
}
]
}
},
// 编辑模态框
{
"componentName": "Modal",
"props": {
"visible": "${store.modalVisible}",
"title": "${store.selectedUser ? '编辑用户' : '新增用户'}"
},
"events": {
"onCancel": {
"type": "callMethod",
"payload": { "method": "handleModalClose" }
}
},
"children": [
{
"componentName": "Form",
"props": {
"initialValues": "${store.selectedUser}"
}
}
]
}
]
}
}
数据流分析:
1. 页面加载
↓
lifeCycles.onMount 触发
↓
setStore({ loading: true })
↓
fetchDataSource('userList')
↓
请求 /api/users
↓
dataSource.userList.data 更新
↓
Table 组件的 dataSource="${dataSource.userList.data}" 自动更新
2. 用户点击"删除"按钮
↓
触发 onClick 事件
↓
callMethod('handleDelete', [userId])
↓
执行 actions 序列:
- confirm() → 用户确认
- request(DELETE /api/users/123)
- message('删除成功')
- fetchDataSource('userList') → 刷新列表
↓
GlobalStore 更新
↓
所有依赖的组件自动重新渲染
3. 用户点击"编辑"按钮
↓
callMethod('handleEdit', [userObject])
↓
setStore({
selectedUser: userObject,
modalVisible: true
})
↓
Modal 的 visible="${store.modalVisible}" → 显示弹窗
Form 的 initialValues="${store.selectedUser}" → 填充数据