十五万字长文 - 由浅入深设计一套低代码平台(2)

19 阅读3分钟

低代码平台架构设计方案 - 从浅入深完整指南(2)

前言: 本文系统阐述了一套完整的低代码平台架构设计方案,涵盖从基础架构到企业级应用的全链路技术实现。

核心内容:

🏗️ 四层架构体系:可视化设计器、Schema协议、运行时引擎、物料体系的完整设计

🔄 全局状态管理:基于Zustand的页面级Store架构,支持跨组件数据流动

⚡ 性能优化方案:三种发布模式(纯运行时、Schema编译、混合模式)对比与实践

🎯 动作系统:枚举化业务操作设计,实现配置化与安全性的平衡

🔧 Schema编译器:深度解析编译优化策略,在保持Runtime架构一致性的同时实现70%体积优化

🚀 SSR支持:Next.js集成方案,满足SEO与首屏性能需求

📦 发布流程:从Schema保存到产物部署的完整工程化实践

适合人群:前端架构师、低代码平台开发者、对前端工程化感兴趣的技术人员

全文15万+字,涵盖架构设计、核心实现、性能优化、工程实践等多个维度,提供可直接落地的技术方案。

阶段二:物料独立 - 插件化架构

核心改进: 物料抽离为独立NPM包,支持按需加载 解决问题: 物料复用、按需加载、第三方扩展

3.1 架构演进

阶段一(单体):
┌─────────────────────────────────┐
│   lowcode-platform              │
│   ├── designer/                 │
│   ├── renderer/                 │
│   └── materials/ (内置)         │
└─────────────────────────────────┘

                ↓ 演进

阶段二(物料独立):
┌────────────────────┐     ┌──────────────────┐
│ lowcode-platform   │     │  Material Packages│
│ ├── designer/      │     │  @lc/button      │
│ ├── renderer/      │ <-- │  @lc/table       │
│ └── material-      │     │  @lc/form        │
│     registry/      │     │  ...             │
└────────────────────┘     └──────────────────┘

3.2 物料包结构

@lowcode-materials/button/
├── src/
│   ├── Button.jsx           # 组件实现
│   └── index.js             # 导出
│
├── lowcode-meta.json        # 物料元信息
├── package.json
└── README.md

# lowcode-meta.json
{
  "name": "Button",
  "title": "按钮",
  "category": "basic",
  "version": "1.0.0",
  "main": "dist/index.js",
  "props": [
    {
      "name": "type",
      "title": "类型",
      "setter": "SelectSetter",
      "options": ["primary", "default", "danger"]
    }
  ],
  "snippets": {
    "componentName": "Button",
    "props": { "type": "primary", "children": "按钮" }
  }
}

3.3 物料注册表

// material-registry/MaterialRegistry.js
class MaterialRegistry {
  constructor() {
    this.materials = new Map();    // 已加载的物料
    this.metadata = new Map();     // 物料元信息
  }

  // 注册物料
  register(packageName, config) {
    const { component, meta } = config;

    this.materials.set(meta.name, component);
    this.metadata.set(meta.name, {
      packageName,
      ...meta
    });

    console.log(`✅ Material registered: ${meta.name}`);
  }

  // 获取组件
  getComponent(componentName) {
    return this.materials.get(componentName);
  }

  // 获取元信息
  getMeta(componentName) {
    return this.metadata.get(componentName);
  }

  // 获取所有物料列表(用于设计器展示)
  getAllMaterials() {
    return Array.from(this.metadata.values());
  }

  // 动态加载物料包
  async loadMaterialPackage(packageName) {
    try {
      // 方式1: 从CDN加载
      const module = await this.loadFromCDN(packageName);

      // 方式2: 通过import动态导入
      // const module = await import(packageName);

      this.register(packageName, module.default);
      return true;
    } catch (error) {
      console.error(`Failed to load material: ${packageName}`, error);
      return false;
    }
  }

  // 从CDN加载物料
  async loadFromCDN(packageName, version = 'latest') {
    const url = `https://cdn.example.com/materials/${packageName}@${version}/index.js`;

    return new Promise((resolve, reject) => {
      const script = document.createElement('script');
      script.src = url;
      script.onload = () => {
        // 假设物料包挂载到 window.LowCodeMaterials
        const module = window.LowCodeMaterials[packageName];
        resolve(module);
      };
      script.onerror = reject;
      document.head.appendChild(script);
    });
  }
}

export default new MaterialRegistry();

3.4 渲染引擎升级(支持动态物料)

// renderer/Renderer.jsx (升级版)
import React from 'react';
import MaterialRegistry from '../material-registry/MaterialRegistry';

class Renderer extends React.Component {
  constructor(props) {
    super(props);
    this.schema = props.schema;
    this.state = {
      loading: true,
      error: null
    };
  }

  async componentDidMount() {
    // 预加载Schema中用到的所有物料
    await this.preloadMaterials();
  }

  // 预加载物料
  async preloadMaterials() {
    const materialsNeeded = this.collectMaterials(this.schema.componentTree);

    for (const componentName of materialsNeeded) {
      // 检查是否已加载
      if (!MaterialRegistry.getComponent(componentName)) {
        const meta = MaterialRegistry.getMeta(componentName);
        if (meta?.packageName) {
          await MaterialRegistry.loadMaterialPackage(meta.packageName);
        }
      }
    }

    this.setState({ loading: false });
  }

  // 收集Schema中使用的所有组件名
  collectMaterials(node, set = new Set()) {
    if (node.componentName) {
      set.add(node.componentName);
    }
    node.children?.forEach(child => this.collectMaterials(child, set));
    return set;
  }

  // 渲染节点
  renderNode(nodeSchema) {
    const { componentName, props, children, id } = nodeSchema;

    // 从注册表获取组件
    const Component = MaterialRegistry.getComponent(componentName);

    if (!Component) {
      return <div>Component {componentName} not found</div>;
    }

    const childNodes = children?.map(child => this.renderNode(child));

    return React.createElement(
      Component,
      { key: id, ...props },
      childNodes
    );
  }

  render() {
    if (this.state.loading) {
      return <div>Loading materials...</div>;
    }

    return this.renderNode(this.schema.componentTree);
  }
}

3.5 物料开发工具

为了让开发者方便地开发物料,提供脚手架工具:

# 创建物料项目
npx @lowcode/create-material my-button

# 项目结构
my-button/
├── src/
│   └── index.jsx
├── demo/                    # 本地预览
│   └── demo.jsx
├── lowcode-meta.json        # 物料元信息
├── package.json
└── README.md
// 物料开发模板
// src/index.jsx
import React from 'react';

function MyButton({ type, children, onClick }) {
  return (
    <button
      className={`my-btn my-btn-${type}`}
      onClick={onClick}
    >
      {children}
    </button>
  );
}

// 导出配置
export default {
  component: MyButton,
  meta: {
    name: 'MyButton',
    title: '自定义按钮',
    category: 'custom',
    props: [
      {
        name: 'type',
        title: '类型',
        setter: 'SelectSetter',
        options: ['primary', 'secondary']
      }
    ],
    snippets: {
      componentName: 'MyButton',
      props: { type: 'primary', children: '点击' }
    }
  }
};

3.6 物料发布流程

# 1. 开发物料
cd my-button
npm run dev        # 本地预览

# 2. 构建
npm run build      # 输出到 dist/

# 3. 发布到NPM
npm publish

# 4. 在低代码平台中安装
npm install @lowcode-materials/my-button

# 5. 注册到平台
import MyButton from '@lowcode-materials/my-button';
MaterialRegistry.register('@lowcode-materials/my-button', MyButton);

3.7 物料市场

提供一个物料市场,让开发者可以浏览、安装物料:

// 物料市场API
class MaterialMarket {
  // 搜索物料
  async search(keyword) {
    const response = await fetch(`/api/materials/search?q=${keyword}`);
    return response.json();
  }

  // 安装物料
  async install(packageName) {
    // 方式1: 后端NPM安装
    await fetch('/api/materials/install', {
      method: 'POST',
      body: JSON.stringify({ packageName })
    });

    // 方式2: 前端动态加载
    await MaterialRegistry.loadMaterialPackage(packageName);
  }

  // 获取物料详情
  async getDetail(packageName) {
    const response = await fetch(`/api/materials/${packageName}`);
    return response.json();
  }
}

3.8 阶段二总结

优点:

  • ✅ 物料独立,可复用和发布
  • ✅ 支持按需加载,减小打包体积
  • ✅ 第三方可以开发和发布物料
  • ✅ 物料可以单独版本管理

缺点:

  • ❌ 物料版本管理复杂
  • ❌ 缺少统一的构建规范
  • ❌ 物料质量参差不齐
  • ❌ 依赖管理困难

适用场景:

  • 中型团队(5-20人)
  • 需要物料复用
  • 有第三方物料接入需求