低代码平台架构设计方案 - 从浅入深完整指南(4-5)
前言: 本文系统阐述了一套完整的低代码平台架构设计方案,涵盖从基础架构到企业级应用的全链路技术实现
核心内容:
🏗️ 四层架构体系:可视化设计器、Schema协议、运行时引擎、物料体系的完整设计
🔄 全局状态管理:基于Zustand的页面级Store架构,支持跨组件数据流动
⚡ 性能优化方案:三种发布模式(纯运行时、Schema编译、混合模式)对比与实践
🎯 动作系统:枚举化业务操作设计,实现配置化与安全性的平衡
🔧 Schema编译器:深度解析编译优化策略,在保持Runtime架构一致性的同时实现70%体积优化
🚀 SSR支持:Next.js集成方案,满足SEO与首屏性能需求
📦 发布流程:从Schema保存到产物部署的完整工程化实践
适合人群:前端架构师、低代码平台开发者、对前端工程化感兴趣的技术人员
全文15万+字,涵盖架构设计、核心实现、性能优化、工程实践等多个维度,提供可直接落地的技术方案。
5.12.9 Schema 编译器深度实现(方案B详解)
对于 C 端高性能场景,编译方案是最优选择。编译器的核心目标是:保持 Runtime 架构不变,优化依赖加载方式,将运行时的动态加载转换为编译时的静态引入。
核心原则:
- ✅ 保持 GlobalStoreManager、ExpressionEngine、Renderer 等核心架构
- ✅ Schema 内联到代码中(避免网络请求)
- ✅ 物料静态引入(支持 Tree Shaking)
- ✅ 动作静态引入(避免动态查找)
- ✅ 使用精简版 Runtime(移除动态加载逻辑)
- ❌ 不转换为原生 React 代码(保持架构一致性)
编译器架构设计
编译器采用三阶段架构,专注于依赖分析和代码生成:
// packages/compiler/src/Compiler.js
class SchemaCompiler {
constructor(options = {}) {
this.options = {
runtimePackage: '@lowcode/runtime-slim', // 使用精简版 Runtime
outputFormat: 'esm',
minify: true,
...options
};
// 编译器三阶段流水线
this.pipeline = [
new SchemaValidator(), // 1. Schema 验证
new DependencyAnalyzer(), // 2. 依赖分析(物料、动作)
new CodeGenerator() // 3. 生成代码(保持 Runtime 架构)
];
}
/**
* 编译 Schema 为优化的 React 组件
* @param {Object} schema - Schema JSON
* @returns {CompileResult}
*/
async compile(schema) {
let context = { schema, options: this.options };
// 执行编译流水线
for (const stage of this.pipeline) {
context = await stage.execute(context);
}
return {
success: true,
code: context.generatedCode, // 生成的 React 组件代码
dependencies: context.dependencies // 依赖清单
};
}
}
阶段1:Schema 验证
// packages/compiler/src/stages/SchemaValidator.js
class SchemaValidator {
async execute(context) {
const { schema } = context;
// 验证 Schema 基本结构
if (!schema.id || !schema.componentTree) {
throw new Error('Invalid schema: missing required fields');
}
// Schema 直接传递,不做结构转换
return { ...context };
}
}
阶段2:依赖分析
编译器的核心工作是分析 Schema 中用到的物料和动作,生成静态 import 语句:
// packages/compiler/src/stages/DependencyAnalyzer.js
class DependencyAnalyzer {
async execute(context) {
const { schema } = context;
// 递归分析组件树,提取所有用到的物料
const materials = this.analyzeMaterials(schema.componentTree);
// 分析方法中用到的动作
const actions = this.analyzeActions(schema.methods || {});
const dependencies = {
materials, // { 'antd': ['Button', 'Table'], ... }
actions // Set(['request', 'confirm', 'message', ...])
};
return { ...context, dependencies };
}
/**
* 递归遍历组件树,收集所有物料
*/
analyzeMaterials(tree) {
const materials = new Map();
const traverse = (node) => {
const { componentName, children } = node;
// 记录物料使用
const library = this.resolveLibrary(componentName); // 'Button' → 'antd'
if (!materials.has(library)) {
materials.set(library, new Set());
}
materials.get(library).add(componentName);
// 递归子节点
if (children) {
children.forEach(child => traverse(child));
}
};
traverse(tree);
// 转换为对象格式
const result = {};
materials.forEach((components, library) => {
result[library] = Array.from(components);
});
return result;
}
/**
* 分析方法中用到的动作类型
*/
analyzeActions(methods) {
const actions = new Set();
Object.values(methods).forEach(method => {
method.actions?.forEach(action => {
actions.add(action.type); // 'request', 'confirm', 'setState', ...
});
});
return actions;
}
/**
* 根据组件名推断所属的物料库
*/
resolveLibrary(componentName) {
// 简化示例:实际需要查询物料注册表
const antdComponents = ['Button', 'Table', 'Form', 'Modal', 'Input'];
if (antdComponents.includes(componentName)) {
return 'antd';
}
return '@lowcode/materials';
}
}
阶段3:代码生成
生成包含 Runtime 渲染器的 React 组件:
// packages/compiler/src/stages/CodeGenerator.js
class CodeGenerator {
async execute(context) {
const { schema, dependencies, options } = context;
// 生成 import 语句
const imports = this.generateImports(dependencies, options.runtimePackage);
// 生成预注册代码
const registrations = this.generateRegistrations(dependencies);
// Schema 内联(序列化为 JavaScript 对象)
const schemaCode = this.serializeSchema(schema);
// 组装完整代码
const generatedCode = \`
\${imports}
/**
* \${schema.name || schema.id}
* Auto-generated by @lowcode/compiler
*
* ⚠️ 架构说明:
* - 使用精简版 Runtime(移除动态加载逻辑)
* - Schema 内联(避免网络请求)
* - 物料静态引入(支持 Tree Shaking)
* - 动作静态引入(避免运行时查找)
*
* ✅ 核心架构与运行时模式完全一致:
* - GlobalStoreManager:全局状态管理
* - ExpressionEngine:表达式解析
* - Renderer:组件渲染
* - EventHandler:事件处理
*/
// Schema 内联
const schema = \${schemaCode};
\${registrations}
export default function \${this.toPascalCase(schema.id)}Page() {
return (
<LowCodeRenderer
schema={schema}
materials={materials}
actions={actions}
/>
);
}
\`.trim();
return { ...context, generatedCode };
}
/**
* 生成 import 语句
*/
generateImports(dependencies, runtimePackage) {
const lines = [];
// 1. 导入 React
lines.push("import React from 'react';");
// 2. 导入精简版 Runtime
lines.push(\`import { LowCodeRenderer } from '\${runtimePackage}';\`);
// 3. 导入物料(静态引入,支持 Tree Shaking)
Object.entries(dependencies.materials).forEach(([library, components]) => {
lines.push(\`import { \${components.join(', ')} } from '\${library}';\`);
});
// 4. 导入动作实现
const actionsList = Array.from(dependencies.actions);
if (actionsList.length > 0) {
const actionImports = actionsList.map(action => \`\${action}Action\`).join(', ');
lines.push(\`import { \${actionImports} } from '@lowcode/actions';\`);
}
return lines.join('\n');
}
/**
* 生成预注册代码
*/
generateRegistrations(dependencies) {
const code = [];
// 物料预注册
code.push('// 物料预注册(避免动态加载)');
code.push('const materials = {');
Object.values(dependencies.materials).flat().forEach(comp => {
code.push(\` \${comp},\`);
});
code.push('};');
code.push('');
// 动作预注册
const actionsList = Array.from(dependencies.actions);
if (actionsList.length > 0) {
code.push('// 动作预注册(避免运行时查找)');
code.push('const actions = {');
actionsList.forEach(action => {
code.push(\` \${action}: \${action}Action,\`);
});
code.push('};');
}
return code.join('\n');
}
/**
* 序列化 Schema 为 JavaScript 对象
*/
serializeSchema(schema) {
return JSON.stringify(schema, null, 2);
}
toPascalCase(str) {
return str.replace(/(^\w|-\w)/g, s => s.replace('-', '').toUpperCase());
}
}
完整示例:编译前后对比
输入:运行时模式的页面组件
// 运行时模式:需要动态加载 Schema 和物料
import { LowCodeRenderer } from '@lowcode/runtime'; // 200KB
export default function RuntimePage() {
const [schema, setSchema] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// 1. 网络请求加载 Schema(~200ms)
fetch('/api/schema?route=/user-manage')
.then(res => res.json())
.then(data => {
setSchema(data);
setLoading(false);
});
}, []);
if (loading) return <div>Loading...</div>;
// 2. Runtime 内部动态加载物料和动作(~300ms)
return <LowCodeRenderer schema={schema} />;
}
输出:编译模式的页面组件
// 编译模式:所有依赖静态引入
import React from 'react';
import { LowCodeRenderer } from '@lowcode/runtime-slim'; // 50KB(精简版)
import { Button, Table } from 'antd'; // 静态引入物料
import { requestAction, confirmAction, messageAction, setStateAction } from '@lowcode/actions'; // 静态引入动作
/**
* 用户管理页面
* Auto-generated by @lowcode/compiler
*
* ⚠️ 架构说明:
* - 使用精简版 Runtime(移除动态加载逻辑)
* - Schema 内联(避免网络请求)
* - 物料静态引入(支持 Tree Shaking)
* - 动作静态引入(避免运行时查找)
*
* ✅ 核心架构与运行时模式完全一致:
* - GlobalStoreManager:全局状态管理
* - ExpressionEngine:表达式解析
* - Renderer:组件渲染
* - EventHandler:事件处理
*/
// Schema 内联(避免网络请求)
const schema = {
"id": "user-manage",
"name": "用户管理页面",
"store": {
"users": [],
"loading": false
},
"methods": {
"loadUsers": {
"params": [],
"actions": [
{ "type": "setState", "payload": { "loading": true } },
{
"type": "request",
"method": "GET",
"url": "/api/users",
"successAction": {
"type": "setState",
"payload": { "users": "\${response.data}", "loading": false }
}
}
]
},
"handleDelete": {
"params": ["userId"],
"actions": [
{ "type": "confirm", "message": "确认删除该用户?" },
{
"type": "request",
"method": "DELETE",
"url": "/api/users/\${userId}",
"successAction": { "type": "message", "content": "删除成功" }
},
{ "type": "method", "method": "loadUsers" }
]
}
},
"lifecycle": {
"onLoad": [{ "type": "method", "method": "loadUsers" }]
},
"componentTree": {
"componentName": "div",
"props": { "className": "page" },
"children": [
{
"componentName": "Button",
"props": { "type": "primary", "loading": "\${store.loading}" },
"events": { "onClick": { "type": "method", "method": "loadUsers" } },
"children": [{ "componentName": "text", "value": "刷新" }]
},
{
"componentName": "Table",
"props": {
"dataSource": "\${store.users}",
"loading": "\${store.loading}"
}
}
]
}
};
// 物料预注册(避免动态加载)
const materials = {
Button,
Table,
};
// 动作预注册(避免运行时查找)
const actions = {
request: requestAction,
confirm: confirmAction,
message: messageAction,
setState: setStateAction,
};
export default function UserManagePage() {
return (
<LowCodeRenderer
schema={schema}
materials={materials}
actions={actions}
/>
);
}
Runtime 分层设计
为了支持编译模式,Runtime 需要分为两个版本:
// packages/runtime/src/index.js (完整版 - 用于运行时渲染)
export { LowCodeRenderer } from './Renderer';
export { MaterialLoader } from './MaterialLoader'; // 动态加载物料
export { ActionRegistry } from './ActionRegistry'; // 动作注册表
export { SchemaLoader } from './SchemaLoader'; // Schema 加载器
// 体积:~200KB
// packages/runtime-slim/src/index.js (精简版 - 用于编译模式)
export { LowCodeRenderer } from '../runtime/src/Renderer';
// ❌ 不包含 MaterialLoader(物料已静态引入)
// ❌ 不包含 ActionRegistry(动作已静态引入)
// ❌ 不包含 SchemaLoader(Schema 已内联)
// 体积:~50KB(减少 75%)
LowCodeRenderer 支持预注册
// packages/runtime/src/Renderer.jsx
export function LowCodeRenderer({ schema, materials, actions }) {
const [runtime] = useState(() => {
// 创建 Runtime 实例
const rt = new LowCodeRuntime(schema);
// 如果提供了预注册的物料,直接使用(编译模式)
if (materials) {
rt.materialRegistry.registerBatch(materials);
}
// 如果提供了预注册的动作,直接使用(编译模式)
if (actions) {
rt.actionRegistry.registerBatch(actions);
}
return rt;
});
// 渲染逻辑完全一致(运行时模式和编译模式共享同一套渲染逻辑)
return renderComponentTree(runtime, schema.componentTree);
}
性能对比:运行时 vs 编译
| 指标 | 运行时渲染 | 编译模式 | 性能提升 |
|---|---|---|---|
| Schema 加载 | `fetch('/api/schema')` ~200ms | 内联(0ms) | 100% ↓ |
| 物料加载 | 动态 `import()` ~300ms | 静态 `import`(Webpack处理) | 100% ↓ |
| 动作查找 | `ActionRegistry.get('request')` ~1ms | 直接引用 `requestAction` | 100% ↓ |
| Runtime 体积 | 200KB(含加载逻辑) | 50KB(精简版) | 75% ↓ |
| 首屏 JS 总体积 | 220KB(Runtime 200KB + Schema 20KB) | 80KB(Runtime 50KB + Code 30KB) | 64% ↓ |
| 首次加载时间 | 2.5s | 0.8s | 68% ↓ |
| GlobalStore | ✅ GlobalStoreManager | ✅ GlobalStoreManager(一致) | - |
| 表达式解析 | ✅ ExpressionEngine | ✅ ExpressionEngine(一致) | - |
| 事件处理 | ✅ EventHandler | ✅ EventHandler(一致) | - |
| 跨组件数据共享 | ✅ `${store.xxx}` | ✅ `${store.xxx}`(一致) | - |
关键发现:
- ✅ 性能提升来自依赖优化,不是架构改变
- ✅ 核心架构(Store、表达式、事件)完全一致
- ✅ 跨组件数据流向机制保持不变
- ✅ 开发和维护成本最低
集成到发布流程
// 发布接口
app.post('/api/pages/:id/publish', async (req, res) => {
const { id } = req.params;
const { schema, publishMode } = req.body;
if (publishMode === 'compile') {
// 方案B:编译模式
const compiler = new SchemaCompiler({
runtimePackage: '@lowcode/runtime-slim',
outputFormat: 'esm',
minify: true
});
const result = await compiler.compile(schema);
if (result.success) {
// 写入文件系统
const outputPath = path.join(__dirname, \`../pages/\${id}.jsx\`);
await fs.writeFile(outputPath, result.code);
// 触发 Webpack/Vite 构建
await buildPage(id);
res.json({
success: true,
mode: 'compile',
entry: \`/pages/\${id}.js\`,
dependencies: result.dependencies
});
}
} else {
// 方案A:运行时模式
await db.pageVersions.create({
pageId: id,
schema: schema,
mode: 'runtime'
});
res.json({ success: true, mode: 'runtime' });
}
});
编译方案的优势
- 性能最优:消除动态加载开销,首屏时间减少 68%
- 体积最小:Tree Shaking 剔除未使用的物料,体积减少 64%
- 架构一致:核心逻辑与运行时模式完全相同,维护成本低
- 调试友好:生成的是标准 React 代码,有完整的 Source Map
- SEO 友好:可进行 SSR/SSG 等服务端渲染优化
- 独立部署:编译产物可独立部署到 CDN
编译方案的劣势
- 失去热更新:修改 Schema 后需重新编译和部署
- 构建时间:编译过程需要 1-3 秒(可通过增量编译优化)
服务端渲染(SSR)支持
编译模式的重要优势之一是天然支持 SSR/SSG,这是运行时模式难以实现的。
为什么编译模式适合 SSR?
// 编译后的组件是标准 React 组件
export default function UserManagePage() {
return (
<LowCodeRenderer
schema={schema}
materials={materials}
actions={actions}
/>
);
}
// ✅ 可以直接用于 Next.js
// pages/user-manage.jsx (Next.js App Router)
export default UserManagePage;
// ✅ 支持 SSR
export async function getServerSideProps() {
// 可以在服务端预加载数据
const users = await fetchUsers();
return {
props: {
initialData: { users }
}
};
}
// ✅ 支持 SSG
export async function getStaticProps() {
const users = await fetchUsers();
return {
props: { initialData: { users } },
revalidate: 60 // ISR: 每60秒重新生成
};
}
Runtime 需要支持 SSR
为了在服务端渲染,Runtime 需要:
- 避免浏览器 API 依赖
// packages/runtime-slim/src/Renderer.jsx
export function LowCodeRenderer({ schema, materials, actions, initialData }) {
const [runtime] = useState(() => {
const rt = new LowCodeRuntime(schema);
rt.materialRegistry.registerBatch(materials);
rt.actionRegistry.registerBatch(actions);
// ✅ 如果有服务端预加载的数据,初始化到 Store
if (initialData) {
rt.storeManager.updateStore(initialData);
}
return rt;
});
// ⚠️ 避免在 render 阶段使用浏览器 API
// ❌ window.location
// ❌ document.cookie
// ❌ localStorage
// ✅ 使用 useEffect 包裹浏览器 API
useEffect(() => {
if (typeof window !== 'undefined') {
// 客户端才执行的逻辑
}
}, []);
return renderComponentTree(runtime, schema.componentTree);
}
- 动作系统的 SSR 适配
// packages/actions/src/requestAction.js
export async function requestAction(config, context) {
const { url, method, data } = config;
// ✅ 服务端和客户端都可以用 fetch
const response = await fetch(url, {
method,
body: data ? JSON.stringify(data) : undefined,
headers: {
'Content-Type': 'application/json',
// ⚠️ 服务端请求需要处理认证
...(context.isServer && context.cookies ? {
'Cookie': context.cookies
} : {})
}
});
return response.json();
}
- SSR 时的数据预加载
// 发布时生成支持 SSR 的代码
class SSRCodeGenerator extends CodeGenerator {
generateCode(schema) {
const code = super.generateCode(schema);
// 分析 lifecycle.onLoad 中的数据请求
const dataFetchActions = this.analyzeDataFetch(schema.lifecycle?.onLoad);
// 生成 getServerSideProps
const ssrCode = this.generateSSRFunction(dataFetchActions);
return code + '\n\n' + ssrCode;
}
generateSSRFunction(dataFetchActions) {
return `
// SSR 数据预加载
export async function getServerSideProps(context) {
try {
// 在服务端预执行数据请求
${dataFetchActions.map(action => `
const ${action.key} = await fetch('${action.url}', {
headers: {
cookie: context.req.headers.cookie || ''
}
}).then(r => r.json());
`).join('\n')}
return {
props: {
initialData: {
${dataFetchActions.map(a => a.key).join(',\n ')}
}
}
};
} catch (error) {
return { props: { initialData: {} } };
}
}
`;
}
}
完整的 SSR 示例
编译产物(支持 Next.js)
// pages/user-manage.jsx
import React from 'react';
import { LowCodeRenderer } from '@lowcode/runtime-slim';
import { Button, Table } from 'antd';
import { requestAction, messageAction } from '@lowcode/actions';
const schema = {
"id": "user-manage",
"store": {
"users": [],
"loading": false
},
"methods": {
"loadUsers": {
"actions": [
{ "type": "request", "url": "/api/users" }
]
}
},
"lifecycle": {
"onLoad": [{ "type": "method", "method": "loadUsers" }]
},
"componentTree": {
"componentName": "div",
"children": [
{
"componentName": "Table",
"props": { "dataSource": "${store.users}" }
}
]
}
};
const materials = { Button, Table };
const actions = { request: requestAction, message: messageAction };
export default function UserManagePage({ initialData }) {
return (
<LowCodeRenderer
schema={schema}
materials={materials}
actions={actions}
initialData={initialData} // 服务端预加载的数据
/>
);
}
// SSR:每次请求时在服务端获取数据
export async function getServerSideProps(context) {
try {
const users = await fetch('https://api.example.com/users', {
headers: {
cookie: context.req.headers.cookie || ''
}
}).then(r => r.json());
return {
props: {
initialData: { users }
}
};
} catch (error) {
return { props: { initialData: {} } };
}
}
// 或者 SSG:构建时生成静态页面
/*
export async function getStaticProps() {
const users = await fetch('https://api.example.com/users').then(r => r.json());
return {
props: { initialData: { users } },
revalidate: 60 // ISR: 60秒后重新生成
};
}
*/
性能对比:CSR vs SSR
| 指标 | 编译模式 CSR | 编译模式 SSR | 提升 |
|---|---|---|---|
| 首屏内容渲染 | 客户端请求数据后渲染 | 服务端直接返回 HTML | FCP 减少 60% |
| SEO | ⚠️ 需要等 JS 执行 | ✅ 搜索引擎直接抓取 | SEO 友好 |
| LCP | ~2s(等待 JS + 数据) | ~0.5s(HTML 已渲染) | 75% ↓ |
| TTI | ~3s | ~1.5s | 50% ↓ |
| 弱网环境 | ❌ 体验差 | ✅ 体验好 | 显著提升 |
业界实践
- 阿里低代码引擎:支持 SSR,通过
@alilc/lowcode-engine-ssr包实现 - 百度 Amis:支持服务端渲染,用于 SEO 敏感场景
- 腾讯 TMagic:提供 SSR 方案用于 H5 营销页面
- 现代电商平台:商品详情页大量使用低代码 + SSR(性能和 SEO 双重要求)
SSR 的关键优势
- SEO 优化:搜索引擎可以直接抓取完整 HTML
- 首屏速度:减少客户端渲染等待时间
- 弱网友好:减少客户端 JS 执行负担
- 社交分享:Open Graph 元数据可以被正确解析
SSR 的适用场景
- ✅ 营销落地页:需要 SEO + 快速首屏
- ✅ 电商商品页:SEO + 性能双重要求
- ✅ 内容类页面:新闻、博客、文档
- ✅ H5 活动页:移动端性能优化
- ❌ 高度交互页面:后台管理系统(CSR 更合适)
- ❌ 实时数据页面:Dashboard(SSR 收益低)
适用场景
- ✅ C端高频页面:首页、商品详情、列表页等
- ✅ 性能敏感场景:移动端、弱网环境
- ✅ SEO需求页面:营销落地页、内容页
- ❌ 高度动态页面:需要频繁调整的运营活动页
- ❌ 个性化页面:千人千面、A/B测试场景