lowcode-engine 接入运行时指南:在 React 应用中渲染编辑器产出的低代码页面
2026/9/14 18:21:33 网站建设 项目流程

lowcode-engine 接入运行时指南:在 React 应用中渲染编辑器产出的低代码页面

【免费下载链接】lowcode-engineAn enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系项目地址: https://gitcode.com/GitHub_Trending/lo/lowcode-engine

本篇聚焦 lowcode-engine 生产链路的最后一环——“接入运行时”:先讲清编辑器产出的两份数据(资产包 assets 与页面数据 schema),再给出渲染模块@alilc/lowcode-react-renderer从数据转换到<ReactRenderer>落屏的完整操作路径,并结合仓库内packages/react-rendererpackages/renderer-core的源码,深入解析 Props 参数、根组件校验、异常兜底等实现细节,读完即可在自己的 React 工程中消费低代码产出的页面。

编辑器产出:assets 与 schema 两份数据

低代码引擎的编辑器将产出两份数据:

  • 资产包数据 assets:包含物料名称、包名及其获取方式,对应协议中的《低代码引擎资产包协议规范》,详见 assets-spec.md;
  • 页面数据 schema:包含页面结构信息、生命周期和代码信息,对应协议中的《低代码引擎搭建协议规范》,详见 lowcode-spec.md。

拿到这两份数据后,可以直接交由渲染模块出码模块来运行,二者的区别在于:

方案运行时依赖后续维护方式限制
渲染模块依赖资产包数据、页面数据和低代码运行时允许维护者继续用低代码(LowCode)的方式在编辑器中维护运行时需要加载低代码运行时
出码模块不依赖低代码运行时和页面数据直接生成可运行的代码,允许维护者用源码(ProCode)的方式继续维护无法再利用低代码编辑器

即:渲染模块保留了“低代码可维护性”,出码模块则把产物落到标准工程代码里,走常规研发流程。

渲染模块:数据转换规则

渲染模块所需要的数据需要经过编辑器产出数据的一定转换,规则如下:

  • schema:从编辑器产出的projectSchema中拿到componentsTree中的首项,即projectSchema.componentsTree[0]
  • components:根据编辑器产出的资产包assets中、页面projectSchema声明依赖的componentsMap,加载所有依赖的资产包,最后获取资产包的实例并生成“物料 - 资产包”的键值对components

这个过程在官方 Demo 项目的src/preview.tsx中有完整实现,核心逻辑如下:

async function getSchemaAndComponents() { const packages = JSON.parse(window.localStorage.getItem('packages') || ''); const projectSchema = JSON.parse(window.localStorage.getItem('projectSchema') || ''); const { componentsMap: componentsMapArray, componentsTree } = projectSchema; const componentsMap: any = {}; componentsMapArray.forEach((component: any) => { componentsMap[component.componentName] = component; }); const schema = componentsTree[0]; const libraryMap = {}; const libraryAsset = []; packages.forEach(({ package: _package, library, urls, renderUrls }) => { libraryMap[_package] = library; if (renderUrls) { libraryAsset.push(renderUrls); } else if (urls) { libraryAsset.push(urls); } }); const vendors = [assetBundle(libraryAsset, AssetLevel.Library)]; const assetLoader = new AssetLoader(); await assetLoader.load(libraryAsset); const components = await injectComponents(buildComponents(libraryMap, componentsMap)); return { schema, components, }; }

这段代码对应的关键步骤可以拆解为四步:

  1. 解析编辑器产物packages(资产包列表)与projectSchema(页面数据)通常由编辑器保存接口下发,Demo 中通过localStorage模拟持久化;
  2. 构造 componentsMap:将projectSchema.componentsMap数组转成{ componentName: 物料描述 }的映射,它是“页面声明了哪些物料”的清单;
  3. 加载资产包:遍历packages,把每个包的renderUrls(优先)或urls收集进libraryAsset,通过AssetLoader.load()动态加载这些 JS 资源,再把包内导出的组件实例与物料描述buildComponents/injectComponents合并,得到最终的components对象;
  4. 返回渲染入参{ schema, components }<ReactRenderer>的两个核心 Props。

提示:资产包的renderUrls是专为“运行时渲染”准备的产物,urls则是编辑器搭建期产物;Demo 代码中“优先取 renderUrls”正是这个原则的体现。

渲染模块:使用 ReactRenderer 落屏

拿到schemacomponents后,即可在 React 上下文中完成页面渲染:

import React from 'react'; import ReactRenderer from '@alilc/lowcode-react-renderer'; const SamplePreview = () => { return ( <ReactRenderer schema={schema} components={components} /> ); }

两点说明:

  • 此处依赖 React 进行渲染。对 Vue 形态的渲染或编辑器支持,官方曾以 issue 形式跟进讨论(见 lowcode-engine 仓库的 issue 列表),当前仓库内落地的是 React 实现;
  • 仓库内的 packages/react-renderer/demo 目录提供了 compose、dataSource、i18n、list、table 五类可运行的演示场景,每个场景都配有schemas/*.js页面数据与说明文档,可用作schema参数的参考样例。

仓库内实现:ReactRenderer 是怎么注册运行时的

官方渲染模块的包名是@alilc/lowcode-react-renderer,对应源码在 packages/react-renderer/src/index.ts。从源码结构看,这个包本身非常薄,核心工作是给框架无关的@alilc/lowcode-renderer-core注入 React 运行时:

adapter.setRuntime({ Component, PureComponent, createContext, createElement, forwardRef, findDOMNode: ReactDOM.findDOMNode, }); adapter.setRenderers({ PageRenderer: pageRendererFactory(), ComponentRenderer: componentRendererFactory(), BlockRenderer: blockRendererFactory(), AddonRenderer: addonRendererFactory(), TempRenderer: tempRendererFactory(), DivRenderer: blockRendererFactory(), }); adapter.setConfigProvider(ConfigProvider);

这里有三层含义:

  • setRuntime:把 React 的ComponentcreateElement等 API 交给 renderer-core 的 adapter,renderer-core 由此与具体框架解耦,这也是引擎“可扩展到其他 UI 框架”的适配点;
  • setRenderers:注册了 6 个内置渲染器,分别对应 schema 中PageComponentBlockAddonTemp等根/容器类型。注意DivRenderer直接复用了blockRendererFactory(),这与运行时对根组件“兼容乐高区块模板(Div)”的校验逻辑相呼应;
  • setConfigProvider:React 版本使用 Fusion 的ConfigProvider(来自@alifd/next)包裹渲染产物,用于注入localedevice等配置,这也解释了 packages/react-renderer/package.json 中对@alifd/next的运行时依赖。

最后导出的ReactRendererrendererFactory()生成的Renderer类派生,并覆盖了isValidComponent,通过isReactComponentinstanceof Component判定一个导出物是否为合法 React 组件,保证components中混入非组件对象时的行为可控。

根组件校验与异常兜底

renderer-core 的 renderer.tsx 定义了所有渲染器共享的入口类Renderer,其中有几处与“接入运行时”直接相关的行为:

根组件白名单校验(renderer.tsx#L144-L147):

// 兼容乐高区块模板 if (schema.componentName !== 'Div' && !isFileSchema(schema)) { logger.error('The root component name needs to be one of Page、Block、Component, please check the schema: ', schema); return '模型结构异常'; }

也就是说,传入<ReactRenderer schema={...} />的根节点componentName必须是PageBlockComponent(或兼容的Div),否则渲染模块会直接输出“模型结构异常”。这正好印证了上文“schema 取componentsTree[0]”的必要性——根节点就是编辑器产出的文件级 schema。

错误与缺失组件兜底(renderer.tsx#L22-L48):

  • 渲染过程中抛出异常时,componentDidCatch会记录engineRenderError,随后渲染faultComponent(可通过faultComponent/faultComponentMap自定义),默认是一个红框提示“组件渲染异常,请查看控制台日志”;
  • schema 中引用了components里不存在的物料时,会渲染NotFoundComponent,默认以容器组件包裹占位文案;若开启enableStrictNotFoundMode,则只输出纯文本Component Not Found,不再兜底容器。

组件解析顺序(renderer.tsx#L125-L136):查找组件时,业务传入的components会覆盖同名内置渲染器({ ...RENDERER_COMPS, ...components });同时支持${componentName}Renderer这种内置渲染器的回退查找。

ReactRenderer 的 Props 全量说明

官方文档示例只展示了schemacomponents两个最小可用入参。完整的 Props 定义位于 renderer-core 的类型声明 types/index.ts#L96-L182 中的IRendererProps,结合 renderer.tsx#L57-L66 的defaultProps,整理如下:

Prop类型 / 取值默认值说明
schemaIPublicTypeRootSchema \| IPublicTypeNodeSchema{}符合低代码搭建协议的页面数据,根节点须为 Page/Block/Component(或 Div)
componentsRecord<string, IGeneralComponent>{}“物料名 → 组件实例”的键值对,即上文数据转换的最终产物
className/style/idstring/CSSProperties/string \| number-渲染模块最外层容器的样式与 id
localestring-语言,配合 ConfigProvider 生效
messagesRecord<string, any>-多语言语料,配置规范见搭建协议中的国际化部分
appHelperIRendererAppHelperundefined渲染模块全局上下文,其中定义的内容可在低代码代码中通过this访问
componentsMap{ [key: string]: any }-物料描述映射,主要在搭建场景使用,生产环境不需要设置
designMode'live' \| 'design'''设计模式标识
suspendedbooleanfalse渲染模块是否挂起;为true时最外层容器的shouldComponentUpdate始终返回false,用于下钻编辑或多引擎渲染场景
onCompGetRef(schema, ref) => void() => {}组件获取 ref 时的钩子
onCompGetCtx(schema, ref) => void() => {}组件 ctx 更新回调
getSchemaChangedSymbol/setSchemaChangedSymbol() => boolean/(symbol) => void-用于外部标记 schema 是否变更
customCreateElement(Component, props, children) => any原生createElement自定义创建 element 的钩子
rendererName'LowCodeRenderer' \| 'PageRenderer' \| string-标识当前模块的渲染类型
notFoundComponentIGeneralComponent内置占位组件找不到组件时的替代渲染
faultComponent/faultComponentMapIGeneralComponent/Record<string, IGeneralComponent>内置红框提示组件渲染异常时的替代渲染
devicestring-设备信息,透传给 ConfigProvider
thisRequiredInJSEbooleantrueJSExpression 是否只支持使用this访问上下文变量
enableStrictNotFoundModebooleanfalse开启后找不到组件时不再兜底默认容器组件

其中appHelper的类型IRendererAppHelper(types/index.ts#L62-L89)值得单独关注:它允许注入utils(全局公共函数)、constants(全局常量)、location/history(react-router 实例)等,schema 中的JSFunction/JSExpression代码即可通过this.utilsthis.location等访问到它们——这是把低代码页面接入宿主应用路由和工具链的关键通道。

designModesuspended两个参数则主要服务于“编辑器内二次渲染”场景(如区块下钻编辑),纯生产环境接入时可以忽略。

测试与 Demo:如何验证你的接入

仓库自带了可参考的最小用例与快照测试:

  • tests/index.test.tsx:构造一份包含BoxBreadcrumbFormTableDialog等 Fusion 组件的components映射,配合 tests/fixtures/schema/basic.ts 的页面 schema,直接渲染<ReactRenderer schema={schema} components={components} />并对输出做 snapshot 断言;
  • 该 fixture schema 覆盖了页面级dataSourcestatecsslifeCyclesmethods,以及JSFunction(如onClick)、JSExpression(如 Dialog 的visible: { type: 'JSExpression', value: 'this.state.isShowDialog' })等典型低代码特性,可作为校验“运行时是否正确执行了生命周期与代码块”的参考样本;
  • demo 目录下的composedataSourcei18nlisttable五组场景则对应了组合渲染、数据源、国际化、列表与表格等更贴近业务的使用面,每组场景均提供独立的schemas/*.js数据文件。

接入自己的工程时,建议按“先跑通 basic 级别 fixture → 再对照 demo 场景逐项验证数据源/事件/多语言”的顺序做回归。

出码模块:ProCode 路线

与渲染模块相对,出码模块不依赖低代码运行时和页面数据,直接生成可独立运行的工程代码。本仓库中的 modules/code-generator 即出码模块的完整实现,其 solutions 目录提供了 icejs、icejs3、rax-app 三类目标工程形态的解决方案(对应icejs.tsicejs3.tsrax-app.ts),并配套了覆盖 i18n、缺失 import、页面映射等场景的回归测试(见 modules/code-generator/tests/bugfix)。

两条路线的选择建议与文档结论一致:需要保留低代码编辑能力、资产可动态下发时走渲染模块;需要把产物沉淀为标准源码工程、纳入常规 CI/CR 流程时走出码模块。

低代码的生产与消费流程总览

经过“接入编辑器”与“接入运行时”两节,低代码的完整生产消费链路可以概括为:

  1. 生产侧:维护者在低代码编辑器中搭建页面,编辑器产出projectSchema(页面数据)与assets(资产包);
  2. 存储侧:一般需要一个后端项目来保存页面数据信息;如果资产包信息是动态的,也需要一并保存资产包信息;
  3. 消费侧(渲染模块):运行页拉取projectSchemaassets,按前文规则转换为schema+components,交给<ReactRenderer>借助低代码运行时渲染,并允许随时回到编辑器继续维护;
  4. 消费侧(出码模块):将projectSchema交给 code-generator 生成标准工程代码,进入常规源码维护流程。

渲染模块(packages/react-renderer+packages/renderer-core)与出码模块(modules/code-generator)是这份产物图的唯一两个出口,二者共享同一套 schema/assets 协议,这也是 lowcode-engine 生产链路与消费链路能够解耦的前提。

【免费下载链接】lowcode-engineAn enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系项目地址: https://gitcode.com/GitHub_Trending/lo/lowcode-engine

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询