低代码平台架构设计方案 - 从浅入深完整指南(4-1)
前言: 本文系统阐述了一套完整的低代码平台架构设计方案,涵盖从基础架构到企业级应用的全链路技术实现。
核心内容:
🏗️ 四层架构体系:可视化设计器、Schema协议、运行时引擎、物料体系的完整设计
🔄 全局状态管理:基于Zustand的页面级Store架构,支持跨组件数据流动
⚡ 性能优化方案:三种发布模式(纯运行时、Schema编译、混合模式)对比与实践
🎯 动作系统:枚举化业务操作设计,实现配置化与安全性的平衡
🔧 Schema编译器:深度解析编译优化策略,在保持Runtime架构一致性的同时实现70%体积优化
🚀 SSR支持:Next.js集成方案,满足SEO与首屏性能需求
📦 发布流程:从Schema保存到产物部署的完整工程化实践
适合人群:前端架构师、低代码平台开发者、对前端工程化感兴趣的技术人员
全文15万+字,涵盖架构设计、核心实现、性能优化、工程实践等多个维度,提供可直接落地的技术方案。
五、运行时能力设计
核心能力: 事件处理、状态管理、数据流、组件通信 解决问题: 复杂页面逻辑、数据交互、业务流程编排
5.1 运行时核心模块
┌─────────────────────────────────────────────────────────────┐
│ Low-Code Runtime │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Event │ │ State │ │ DataSource │ │
│ │ System │ │ Manager │ │ Manager │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │ │
│ └──────────────────┼──────────────────┘ │
│ ↓ │
│ ┌─────────────────┐ │
│ │ Expression │ │
│ │ Engine │ │
│ └─────────────────┘ │
│ │ │
│ ↓ │
│ ┌─────────────────┐ │
│ │ Action │ │
│ │ Executor │ │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
5.2 Schema扩展协议
在基础Schema基础上,扩展运行时能力:
{
"version": "1.0.0",
"componentTree": { /* 组件树 */ },
// 新增:全局状态Store (基于Zustand实现)
// ⚠️ 注意: 这是全局状态,不是某个组件的useState
// 所有组件都可以通过表达式 ${store.xxx} 访问
"store": {
"userInfo": null,
"loading": false,
"tableData": []
},
// 新增:数据源定义
"dataSources": [
{
"id": "userApi",
"type": "http",
"config": {
"url": "/api/users",
"method": "GET"
}
}
],
// 新增:生命周期钩子
"lifeCycles": {
"onMount": [
{ "type": "setStore", "payload": { "loading": true } },
{ "type": "fetchDataSource", "payload": { "id": "userApi" } }
]
},
// 新增:全局方法定义
// 所有组件的事件都可以通过 callMethod 调用这些方法
"methods": {
"handleDelete": {
"params": ["id"],
"actions": [
{ "type": "confirm", "payload": { "message": "确认删除?" } },
{ "type": "request", "payload": { "url": "/api/users/${id}", "method": "DELETE" } }
]
}
}
}
架构说明:
┌─────────────────────────────────────────────────────────┐
│ LowCodeRuntime (页面级单例) │
│ ┌───────────────────────────────────────────────────┐ │
│ │ GlobalStore (Zustand) │ │
│ │ - 所有状态集中管理 │ │
│ │ - 任意组件可通过表达式访问 │ │
│ │ - 类似 Redux Store,不是组件useState │ │
│ └───────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────┐ │
│ │ GlobalMethods (全局方法表) │ │
│ │ - 定义在顶层,所有组件可调用 │ │
│ │ - 通过 callMethod 动作触发 │ │
│ └───────────────────────────────────────────────────┘ │
└─────────────────┬────────────────────────────────────────┘
│
所有组件通过表达式/事件访问
│
┌────────────┼────────────┐
↓ ↓ ↓
┌─────────┐ ┌─────────┐ ┌─────────┐
│Component│ │Component│ │Component│
│ A │ │ B │ │ C │
└─────────┘ └─────────┘ └─────────┘
5.3 事件系统
事件绑定方式:
{
"componentName": "Button",
"events": {
// 方式1: 简单动作
"onClick": {
"type": "setState",
"payload": { "loading": true }
},
// 方式2: 动作序列
"onClick": [
{ "type": "validateForm", "payload": { "formId": "userForm" } },
{ "type": "request", "payload": { "url": "/api/submit" } },
{ "type": "navigate", "payload": { "url": "/success" } }
],
// 方式3: 调用全局方法
"onClick": {
"type": "callMethod",
"payload": { "method": "handleSubmit" }
}
}
}
事件系统实现:
// runtime/EventSystem.js
class EventSystem {
constructor(runtime) {
this.runtime = runtime;
}
// 创建事件处理器
createEventHandler(nodeId, eventName, eventConfig) {
return async (event, ...args) => {
try {
// 执行事件处理
const result = await this.executeEvent(eventConfig, {
event,
args,
nodeId
});
return result;
} catch (error) {
console.error(`Event execution failed:`, error);
}
};
}
// 执行事件(支持单个动作或动作序列)
async executeEvent(eventConfig, context) {
if (eventConfig.type) {
return await this.executeAction(eventConfig, context);
}
if (Array.isArray(eventConfig)) {
return await this.executeActionSequence(eventConfig, context);
}
}
// 执行单个动作
async executeAction(action, context) {
const executor = this.runtime.actionRegistry.get(action.type);
const payload = this.resolvePayload(action.payload, context);
return await executor.execute(payload, context);
}
// 执行动作序列
async executeActionSequence(actions, context) {
const results = [];
for (const action of actions) {
// 支持条件执行
if (action.condition) {
const shouldExecute = this.runtime.expression.evaluate(
action.condition,
context
);
if (!shouldExecute) continue;
}
const result = await this.executeAction(action, context);
results.push(result);
// 支持错误中断
if (result.error && action.stopOnError) {
break;
}
}
return results;
}
}
5.4 全局状态管理 (Global Store)
核心概念: 使用 Zustand 实现全局状态管理,类似于 Redux,但配置更简单。
⚠️ 重要: 这不是组件级的
useState,而是页面级的全局 Store!
// runtime/GlobalStoreManager.js
import { createStore } from 'zustand';
import { immer } from 'zustand/middleware/immer';
/**
* 全局状态管理器
*
* 架构对比:
* - 传统React: 组件内 useState() → 组件私有状态
* - 低代码平台: GlobalStore → 所有组件共享的全局状态
*
* 类似于:
* - Redux Store (但更轻量)
* - Zustand Store
* - MobX Store
*/
class GlobalStoreManager {
constructor(initialStore = {}) {
// 创建全局 Store
this.store = createStore(
immer((set, get) => ({
...initialStore, // 来自 Schema 的 store 字段
setStore: (updater) => {
set((store) => {
if (typeof updater === 'function') {
updater(store);
} else {
Object.assign(store, updater);
}
});
},
getStore: () => get()
}))
);
}
// 获取状态(支持路径访问)
getStore(path) {
const store = this.store.getState();
if (!path) return store;
// 支持 "user.name" 路径访问
return path.split('.').reduce((obj, key) => obj?.[key], store);
}
// 设置状态
setStore(updates) {
this.store.getState().setStore(updates);
}
// 订阅状态变化 (用于响应式更新)
subscribe(listener) {
return this.store.subscribe(listener);
}
}
/**
* 使用示例:
*
* // Schema 定义
* {
* "store": { "users": [], "loading": false }
* }
*
* // 运行时
* const storeManager = new GlobalStoreManager({ users: [], loading: false });
*
* // 任意组件可访问
* const users = storeManager.getStore('users');
* storeManager.setStore({ loading: true });
*/
5.5 数据源管理
支持HTTP/GraphQL等多种数据源:
// runtime/DataSourceManager.js
class DataSourceManager {
constructor(runtime) {
this.runtime = runtime;
this.dataSources = new Map();
}
// 注册数据源
register(dataSourceConfig) {
const { id, type, config } = dataSourceConfig;
this.dataSources.set(id, {
id,
type,
config,
loading: false,
data: null,
error: null
});
// 自动加载
if (config.autoLoad) {
this.load(id);
}
}
// 加载数据
async load(id, params = {}) {
const dataSource = this.dataSources.get(id);
if (!dataSource) throw new Error(`DataSource "${id}" not found`);
dataSource.loading = true;
this.updateState(id, { loading: true, error: null });
try {
const data = await this.executeLoad(dataSource, params);
dataSource.data = data;
dataSource.loading = false;
this.updateState(id, { data, loading: false });
return data;
} catch (error) {
dataSource.error = error;
this.updateState(id, { loading: false, error: error.message });
throw error;
}
}
// 执行加载
async executeLoad(dataSource, params) {
const { type, config } = dataSource;
switch (type) {
case 'http':
const { url, method = 'GET', headers = {} } = config;
const response = await fetch(this.resolveUrl(url, params), {
method,
headers: { 'Content-Type': 'application/json', ...headers },
body: method !== 'GET' ? JSON.stringify(params.data) : undefined
});
return await response.json();
case 'graphql':
// GraphQL实现
break;
case 'static':
return config.data;
}
}
// 解析URL变量: /api/users/${id}
resolveUrl(url, params) {
return url.replace(/\${(\w+)}/g, (match, key) => {
return params[key] ?? this.runtime.state.getState(key) ?? match;
});
}
// 更新到全局状态
updateState(id, updates) {
this.runtime.state.setState({
[`dataSource_${id}`]: updates
});
}
}
5.6 组件与全局Store的交互
⚠️ 概念澄清: 这里不是传统意义的"父子组件通信"!
在低代码平台中,所有组件都是通过全局Store进行数据交互,而不是通过组件层级的 props 传递。
架构对比:
// 传统React: 父子组件通信
function ParentPage() {
const [users, setUsers] = useState([]); // 父组件的状态
return <UserList users={users} />; // 通过props传递
}
// 低代码平台: 组件与全局Store交互
const schema = {
"store": { "users": [] }, // 全局Store (不属于任何组件)
"componentTree": {
"children": [
{
"componentName": "UserList",
"props": {
"users": "${store.users}" // 从全局Store读取
}
}
]
}
};
1. 组件读取全局状态
{
"componentName": "UserList",
"props": {
// 通过表达式从全局Store读取数据
"users": "${store.users}",
"loading": "${store.loading}",
// 支持计算属性
"userCount": "${store.users.length}",
// 支持复杂表达式
"activeUsers": "${store.users.filter(u => u.active)}"
}
}
2. 组件触发全局方法
{
"componentName": "UserList",
"props": {
"users": "${store.users}",
// onDelete 不是传统的回调函数
// 而是一个事件配置,会调用全局methods中的handleDelete
"onDelete": {
"type": "callMethod",
"payload": { "method": "handleDelete" }
}
}
}
数据流示意图:
┌─────────────────────────────────────────────────────┐
│ 全局 Runtime │
│ ┌─────────────────────────────────────────────┐ │
│ │ GlobalStore: { users: [...], loading: false }│ │
│ └─────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────┐ │
│ │ Methods: { handleDelete: {...} } │ │
│ └─────────────────────────────────────────────┘ │
└────────────┬────────────────────────────────────────┘
│
所有组件通过表达式访问
│
┌──────────┼──────────┐
↓ ↓ ↓
┌─────┐ ┌─────┐ ┌─────────┐
│Button│ │Table│ │UserList │
└─────┘ └─────┘ └─────────┘
│ │
│ onClick │ onDelete
│ │
└────────┬───────────┘
↓
触发全局 handleDelete 方法
↓
更新 GlobalStore.users
↓
所有依赖 store.users 的组件自动重新渲染
2. 兄弟组件通信(EventBus)
// runtime/EventBus.js
class EventBus {
constructor() {
this.events = new Map();
}
// 订阅事件
on(eventName, callback) {
if (!this.events.has(eventName)) {
this.events.set(eventName, []);
}
this.events.get(eventName).push(callback);
return () => this.off(eventName, callback);
}
// 触发事件
async emit(eventName, data) {
const listeners = this.events.get(eventName) || [];
const results = [];
for (const listener of listeners) {
const result = await listener(data);
results.push(result);
}
return results;
}
}
Schema中的通信配置:
{
"componentTree": {
"children": [
// 组件A: 发送消息
{
"componentName": "Button",
"events": {
"onClick": {
"type": "emitEvent",
"payload": {
"eventName": "refreshList",
"data": { "timestamp": "${Date.now()}" }
}
}
}
},
// 组件B: 接收消息
{
"componentName": "Table",
"listeners": {
"refreshList": [
{ "type": "fetchDataSource", "payload": { "id": "tableData" } }
]
}
}
]
}
}
5.7 动作系统 (Action System)
核心问题: 低代码平台中,用户不能直接写 JavaScript 代码,如何实现业务逻辑(如删除、请求接口、显示提示)?
解决方案: 提供预定义的"动作积木",用户通过 JSON 配置来组合使用。
架构设计理念:
传统开发:
用户点击删除 → 写 JS 函数 → 调用 API → 刷新列表
❌ 需要编程能力
低代码平台:
用户点击删除 → 配置动作序列 → 运行时执行 → 自动完成
✅ 无需编程,配置即可
动作系统的三层架构:
┌─────────────────────────────────────────────────┐
│ 用户配置层 (JSON Schema) │
│ { │
│ "events": { │
│ "onClick": [ │
│ { "type": "confirm", "payload": {...} }, │
│ { "type": "request", "payload": {...} }, │
│ { "type": "message", "payload": {...} } │
│ ] │
│ } │
│ } │
└────────────────┬────────────────────────────────┘
│ 运行时解析
↓
┌─────────────────────────────────────────────────┐
│ 动作注册表 (ActionRegistry) │
│ - confirm: 确认对话框 │
│ - request: HTTP 请求 │
│ - message: 消息提示 │
│ - setStore: 更新状态 │
│ - ... │
└────────────────┬────────────────────────────────┘
│ 执行引擎
↓
┌─────────────────────────────────────────────────┐
│ 原生 JavaScript 实现 │
│ async execute(payload) { │
│ await fetch(url, { method, body }) │
│ return response.json() │
│ } │
└─────────────────────────────────────────────────┘
内置15+常用动作:
每个动作都是一个预定义的 JavaScript 函数,用户通过 JSON 配置来调用。
// runtime/ActionRegistry.js
class ActionRegistry {
constructor(runtime) {
this.runtime = runtime;
this.actions = new Map();
this.registerBuiltinActions();
}
/**
* 注册动作
* @param {string} type - 动作类型(如 'confirm', 'request')
* @param {Object} handler - 动作处理器
* @param {Function} handler.execute - 实际执行的函数
*/
register(type, handler) {
this.actions.set(type, handler);
}
/**
* 执行动作
* @param {string} type - 动作类型
* @param {Object} payload - 动作参数
*/
async execute(type, payload) {
const action = this.actions.get(type);
if (!action) {
throw new Error(`Action "${type}" not found`);
}
return await action.execute(payload);
}
registerBuiltinActions() {
// 1. 状态管理
this.register('setStore', {
execute: async (payload) => {
this.runtime.store.setStore(payload);
}
});
// 2. HTTP 请求
this.register('request', {
execute: async ({ url, method = 'GET', data, headers = {} }) => {
console.log(`📡 HTTP ${method} ${url}`);
const response = await fetch(url, {
method,
headers: { 'Content-Type': 'application/json', ...headers },
body: data ? JSON.stringify(data) : undefined
});
const result = await response.json();
console.log(`✅ Response:`, result);
return result;
}
});
// 3. 数据源加载
this.register('fetchDataSource', {
execute: async ({ id, params }) => {
return await this.runtime.dataSource.load(id, params);
}
});
// 4. 页面导航
this.register('navigate', {
execute: async ({ url, replace = false }) => {
replace ? window.location.replace(url) : window.location.href = url;
}
});
// 5. 消息提示
this.register('message', {
execute: async ({ type = 'info', content }) => {
// 集成 Ant Design Message 或其他 UI 库
window.antdMessage?.[type](content);
}
});
// 6. 确认对话框
this.register('confirm', {
execute: async ({ message, title }) => {
// 返回 true/false,可以用于条件执行
return window.confirm(message);
}
});
// 7-8. 弹窗管理
this.register('openModal', {
execute: async ({ modalId }) => {
this.runtime.store.setStore({ [`${modalId}_visible`]: true });
}
});
this.register('closeModal', {
execute: async ({ modalId }) => {
this.runtime.store.setStore({ [`${modalId}_visible`]: false });
}
});
// 9-10. 表单操作
this.register('validateForm', {
execute: async ({ formId }) => {
// 触发表单验证
const form = this.runtime.formRegistry.get(formId);
return await form.validate();
}
});
this.register('resetForm', {
execute: async ({ formId }) => {
const form = this.runtime.formRegistry.get(formId);
form.resetFields();
}
});
// 11. 触发事件(用于组件间通信)
this.register('emitEvent', {
execute: async ({ eventName, data }) => {
await this.runtime.eventBus.emit(eventName, data);
}
});
// 12. 调用全局方法
this.register('callMethod', {
execute: async ({ method, params = [] }) => {
return await this.runtime.callMethod(method, params);
}
});
// 13. 延迟执行
this.register('delay', {
execute: async ({ milliseconds }) => {
await new Promise(resolve => setTimeout(resolve, milliseconds));
}
});
// 14. 条件执行
this.register('condition', {
execute: async ({ condition, thenActions, elseActions }) => {
const shouldExecute = this.runtime.expression.evaluate(condition);
const actions = shouldExecute ? thenActions : elseActions;
if (actions) {
return await this.runtime.eventSystem.executeActionSequence(actions);
}
}
});
// 15. 循环执行
this.register('loop', {
execute: async ({ items, actions }) => {
const results = [];
for (const item of items) {
const result = await this.runtime.eventSystem.executeActionSequence(
actions,
{ item }
);
results.push(result);
}
return results;
}
});
}
}
为什么需要动作系统?
- 降低门槛: 用户不需要会编程,通过配置即可实现业务逻辑
- 标准化: 统一的动作接口,所有操作都是
{ type, payload }的形式 - 可组合: 多个动作可以组成序列,实现复杂逻辑
- 可扩展: 开发者可以注册自定义动作
- 安全可控: 动作在沙箱中执行,避免任意代码执行的风险
使用示例:
// 用户配置(不需要写代码)
{
"events": {
"onClick": [
// 步骤1: 弹出确认框
{
"type": "confirm",
"payload": { "message": "确认删除?" }
},
// 步骤2: 发送 HTTP 请求
{
"type": "request",
"payload": {
"url": "/api/users/123",
"method": "DELETE"
}
},
// 步骤3: 显示成功提示
{
"type": "message",
"payload": {
"type": "success",
"content": "删除成功"
}
},
// 步骤4: 刷新列表
{
"type": "fetchDataSource",
"payload": { "id": "userList" }
}
]
}
}
// 运行时自动执行(用户看不到这部分代码)
async function handleClick() {
// 执行动作序列
const confirmed = await actionRegistry.execute('confirm', {
message: "确认删除?"
});
if (confirmed) {
await actionRegistry.execute('request', {
url: "/api/users/123",
method: "DELETE"
});
await actionRegistry.execute('message', {
type: "success",
content: "删除成功"
});
await actionRegistry.execute('fetchDataSource', {
id: "userList"
});
}
}
自定义动作:
开发者可以注册自定义动作来扩展平台能力:
// 注册自定义上传动作
runtime.actionRegistry.register('customUpload', {
execute: async ({ file, onProgress, onSuccess }) => {
const formData = new FormData();
formData.append('file', file);
const xhr = new XMLHttpRequest();
xhr.upload.onprogress = (e) => {
const percent = (e.loaded / e.total) * 100;
runtime.eventSystem.executeEvent(onProgress, { percent });
};
xhr.onload = () => {
const result = JSON.parse(xhr.responseText);
runtime.eventSystem.executeEvent(onSuccess, { result });
};
xhr.open('POST', '/api/upload');
xhr.send(formData);
}
});
// 用户就可以在 Schema 中使用
{
"events": {
"onChange": {
"type": "customUpload",
"payload": {
"file": "${event.target.files[0]}"
}
}
}
}