
lowcode-engine 中通过 this.utils 扩展第三方工具设计器与预览态的完整实践【免费下载链接】lowcode-engineAn enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系项目地址: https://gitcode.com/GitHub_Trending/lo/lowcode-engine本篇指南围绕 lowcode-engine 官方 FAQ「如何通过 this.utils 使用第三方工具扩展」展开讲解如何把 moment 等第三方工具库注入到搭建运行时使用户在协议表达式JSExpression与组件 function 中通过this.utils.xxx直接调用读完后你将掌握设计器态引擎 API 配置、资产包注入与预览态ReactRenderer appHelper两条完整的接入链路并能从源码层面理解上下文挂载机制。this.utils 的上下文机制appHelper 挂载到容器组件this.utils并不是引擎的魔法属性它的本质是渲染模块的全局上下文appHelper被挂载到了页面容器组件的this上。按照 使用渲染模块 文档的定义appHelper支持以下上下文utils全局公共函数constants全局常量locationreact-router 的location实例historyreact-router 的history实例。在渲染核心层的实现中这一机制体现得非常直接。从源码结构看base.tsx 中容器组件通过 getter 把this的各个上下文转发到props.__appHelperget appHelper(): IRendererAppHelper { return this.props.__appHelper; } get utils() { return this.appHelper?.utils; } get constants() { return this.appHelper?.constants; }因此只要引擎或渲染器拿到appHelper.utils协议中写this.utils.moment(2020-01-01).format(...)就能命中对应工具。而addon层还会做一层合并addon.tsx 的get utils()将appHelper.utils与config.utils做浅合并保证运行时配置优先生效。设计器态一通过引擎 APIinit 的 appHelper配置在 init - 初始化 API 文档中官方给出了「使用 utils 第三方工具扩展」的示例。核心是init的第二个参数engineOptions中的appHelper字段import { init } from alilc/lowcode-engine; init(document.getElementById(engine), { appHelper: { utils: { // 以 moment 为例把第三方工具挂到 utils 下 moment, }, constants: { ENV: prod, }, }, });该字段在类型定义中有明确注释。engine-options.ts 中/** * 与 react-renderer 的 appHelper 一致 */ appHelper?: { /** 全局公共函数 */ utils?: Recordstring, any; /** 全局常量 */ constants?: Recordstring, any; };同时config.ts 中引擎配置表也登记了该选项// 与 react-renderer 的 appHelper 一致 appHelper: { type: object, description: 定义 utils 和 constants 等对象, },配置之后内置模拟器渲染器会把appHelper合并进它的运行时上下文。在 react-simulator-renderer 的 renderer.ts 中可以看到消费链路host.injectionConsumer.consume((data) { const newCtx { ...this._appContext, }; merge(newCtx, data.appHelper || {}); this._appContext newCtx; });injectionConsumer正是接收引擎注入点即init时传入的appHelper的通道合并后的_appContext最终作为渲染器的上下文于是用户在设置面板的 JS 函数 / 变量表达式中即可访问this.utils.moment。设计器态二通过资产包packages 资源配置注入除了initAPI设计器还支持通过资产包方式提供工具库这也是官方 FAQ 中强调的第二种方式在画布中能够访问到 moment 的前提是资产包中已声明了相应资源。资产包的packages声明了「包名 → 全局变量名 → 资源地址」的映射例如为 moment 配置{ packages: [ { package: moment, library: moment, urls: [https://g.alicdn.com/code/lib/moment.js/2.29.4/moment-with-locales.min.js] } ] }其中packagenpm 包名library该库加载到全局作用域后的变量名CDN 脚本暴露的全局变量urls资源地址设计器画布会将其加载进 iframe 环境。从源码看模拟器渲染器在构建utils时会根据libraryMap即 packages 中的package → library映射从全局作用域取回对应库并挂到 utils 上。renderer.ts 中内置上下文的组装过程如下this._appContext { utils: { router: { push(path: string, params?: object) { history.push(withQueryParams(path, params)); }, replace(path: string, params?: object) { history.replace(withQueryParams(path, params)); }, }, legaoBuiltins: { getUrlParams() { const { search } history.location; return parseQuery(search); }, }, i18n: { setLocale: (loc: string) { /* 切换语言 */ }, currentLocale: this.locale, messages: {}, }, // 根据 libraryMap 从全局库中解析出项目级 utils如 moment ...getProjectUtils(this._libraryMap, host.get(utilsMetadata)), }, constants: {}, requestHandlersMap: this._requestHandlersMap, };getProjectUtils(this._libraryMap, ...)就是「资产包 → this.utils」的关键转换libraryMap来自packages资产utilsMetadata则定义了哪些全局库应作为工具函数暴露。这也解释了 FAQ 原文档中「PS」提示的必要性需要在 packages 中有相关的资源配置如urls指向 moment 的 CDN 地址否则在画布中可能会访问不到对应的资源。即资源没加载进画布 iframe全局库不存在getProjectUtils自然取不到工具实例。在搭建协议中使用 this.utils配置完成后this.utils可以在搭建协议的两类场景中使用组件的function生命周期、事件函数与JSExpression变量表达式。官方 renderer 文档 给出了标准示例{ componentName: Button, props: { type: primary, onClick: { type: JSExpression, value: function onClick(e) { this.utils.moment(this.constants.today).format(YYYY-MM-DD); } } }, children: 格式化日期 }配套的渲染侧代码预览态见下节import ReactRenderer from alilc/lowcode-react-renderer; ReactDOM.render(( ReactRenderer schema{schema} components{components} appHelper{{ utils: { moment, }, constants: { today: 2026-01-01, }, }} / ), document.getElementById(root));预览态ReactRenderer 的 appHelper 属性发布后的预览 / 运行态不经过设计器引擎此时this.utils的来源切换为渲染模块自身的appHelper属性。按照 使用渲染模块 的 API 表appHelper是 ReactRenderer 的可选参数Object含义为「渲染模块全局上下文」。一个完整的预览态接入示例摘自 renderer 文档的项目使用示例 并叠加 appHelperimport React, { useState } from react; import ReactDOM from react-dom; import { Loading, Button } from alifd/next; import moment from moment; import { buildComponents, assetBundle, AssetLevel, AssetLoader } from alilc/lowcode-utils; import ReactRenderer from alilc/lowcode-react-renderer; const SamplePreview () { const [data, setData] useState({}); async function init() { 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 assetLoader new AssetLoader(); await assetLoader.load(libraryAsset); const components buildComponents(libraryMap, componentsMap); setData({ schema, components }); } const { schema, components } data; if (!schema || !components) { init(); return Loading fullScreen /; } return ( ReactRenderer schema{schema} components{components} appHelper{{ utils: { moment, // 预览态同样把 moment 挂到 this.utils }, constants: { ENV: prod, }, }} / ); }; ReactDOM.render(SamplePreview /, document.getElementById(root));这里同样体现了「packages 资源声明」的一致性预览态先根据设计器导出的packages加载资源再通过appHelper把工具函数显式注入渲染上下文。两条链路的对照与注意事项维度设计器态预览态入口init(container, { appHelper: { utils, constants } })见 init API 文档ReactRenderer appHelper{{ utils, constants }} /见 渲染模块文档资产包方式packages中声明package / library / urls由getProjectUtils从全局库解析自行assetLoader.load加载urls后手动注入appHelper内置 utilsrouter、legaoBuiltins.getUrlParams、i18n见 renderer.ts由使用方自行注入另可配合location/history上下文消费方画布 iframe 中的模拟器渲染器独立页面中的 ReactRenderer几个实践注意点命名冲突模拟器已内置router、i18n等 utils通过merge合并时renderer.ts用户自定义的同名键会覆盖内置实现命名前应避开或明确知道自己在覆盖什么资源依赖设计器中若走资产包方式urls缺失会导致画布取不到工具FAQ 原文的 PS 提示预览态则需保证assetLoader.load完成后再渲染表达式约束thisRequiredInJSE默认为true表达式须以this访问上下文见 engine-options.ts 的类型注释this.utils.xxx正是该约定下的推荐写法类型来源appHelper的两层结构utils / constants在 engine-options.ts 中有完整类型定义编写 TS 接入代码时可参照。总结来说this.utils是 lowcode-engine 在「设计器—预览」全链路统一暴露第三方工具的标准通道设计器侧靠init的appHelper或资产包packages完成注入预览侧靠 ReactRenderer 的appHelper属性完成注入两者共享同一套上下文挂载机制从而保证用户在搭建协议中写下的this.utils.moment(...)在画布和运行页面表现一致。【免费下载链接】lowcode-engineAn enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系项目地址: https://gitcode.com/GitHub_Trending/lo/lowcode-engine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考