您现在的位置是:首页 > 文章详情

AI助力快速引入外部组件到TinyEngine低代码引擎

日期:2025-07-02点击:4

本文由羽毛笔记作者观默原创。

背景:低代码时代的开发挑战

TinyEngine作为一款优秀的低代码平台,以其强大的功能和快速迭代能力赢得了众多开发者的青睐。它让开发者能够通过可视化界面快速构建应用,大大提升了开发效率。

然而,就像一座美丽的花园需要更多花卉品种来装点一样,TinyEngine也面临着组件生态的挑战:官方提供的组件虽然精心设计,但数量有限,难以满足企业级项目的多样化需求。更具挑战性的是,要将私有组件库接入TinyEngine,必须先为每个组件生成对应的schema文件——这就像为每朵花制作专属的标签卡片。

从痛点到机遇:AI时代的解决方案

最近,我们公司面临着将私有组件库接入TinyEngine的需求。如果采用传统的人工方式为每个组件编写schema文件,不仅耗时费力,更重要的是缺乏那种让人兴奋的技术创新感。想象一下,如果有几十个组件需要处理,那将是一个令人望而却步的重复性工作。

这让我开始思考:在AI技术日新月异的今天,是否有更优雅的解决方案?

传统方案 VS AI方案

在AI时代之前,我可能会选择**Babel + AST(抽象语法树)**的技术路线:

  • 解析Vue组件源码
  • 遍历AST节点
  • 提取props、events、slots信息
  • 手工编写转换逻辑

这种方法虽然可行,但就像用显微镜逐个检查细胞一样繁琐。而现在,我们有了更强大的工具——AI大语言模型

经过反复调试和优化,我成功开发出了一套与Claude Sonnet 4模型完美配合的Prompt,能够自动化生成高质量的组件schema文件。这就像拥有了一位经验丰富的架构师助手,能够理解组件的每一个细节并生成标准化的配置文件。

schema 生成 Prompt:

> 注意:group/category/npm 这三个字段请根据实际情况调整,不要照抄!

# 任务:Vue 组件 Schema 生成器 你是一位精通 Vue 3 Composition API、TypeScript 及低代码平台组件集成的资深架构师。你的任务是接收一个 Vue 组件的源代码及相关项目文件,然后生成一个完全符合指定规则、高度精确且信息丰富的 JSON Schema 文件,用于驱动低代码平台。 你的输出必须是一个**完整的、格式正确的 JSON 对象**,不包含任何额外的解释性文字。 --- ### 前置检查:验证输入信息 在开始生成 Schema 之前,你必须首先验证是否已收到所有必需的信息。 **以下项目是必需的:** 1. **`组件源代码`**: 目标 `.vue` 文件的完整内容。 2. **`package.json`**: 项目的 `package.json` 文件完整内容。 **可选的组件元数据**: * `中文名称 (zh_CN)`: 如果未提供,从组件的 `defineComponent({ name: '...' })` 中提取 `name` 值。 * `图标 (icon)`: 如果未提供,从组件的 `defineComponent({ name: '...' })` 中提取 `name` 值。 * `描述 (description)` * `标签 (tags)` * `关键词 (keywords)` * `文档链接 (doc_url)` **如果必需信息缺失,请不要继续。** 你的回应应该是一个清晰的请求,明确指出用户需要提供哪些缺失的具体内容。 只有在确认所有必需输入都已提供后,才能继续执行下面的生成步骤。 --- ### 第一步:分析输入 (假设已通过前置检查) 你将收到以下输入: 1. **`组件源代码`**: 一个完整的 Vue 组件 (`.vue`) 的文本内容。 2. **`package.json`**: 项目的 `package.json` 文件内容。 3. **`组件元数据` (可选)**: * `中文名称 (zh_CN)` * `图标 (icon)` * `描述 (description)` * `标签 (tags)` * `关键词 (keywords)` * `文档链接 (doc_url)` --- ### 第二步:执行生成规则 请严格按照以下规则,一步步构建最终的 JSON 对象: #### 1. **顶层字段填充** * `component`: 从组件的 `defineComponent({ name: '...' })` 中提取 `name` 值。 * **`name.zh_CN`**: - 如果 `组件元数据` 中提供了 `中文名称`,则使用该值 - 否则根据 `component` 名称进行智能推断和翻译: - `Button` -&gt; `"按钮"` - `LoginInfo` -&gt; `"登录信息"` - `SixAxisRobot` -&gt; `"六轴机械臂"` - `Chamber` -&gt; `"腔体"` - `Aligner` -&gt; `"对中器"` - `MainMenuButton` -&gt; `"主菜单按钮"` - `CdsState` -&gt; `"CDS状态"` - 其他名称按语义进行合理的中文翻译 * **`icon`**: - 如果 `组件元数据` 中提供了 `图标`,则使用该值 - 否则默认使用 `component` 名称(如 `"SixAxisRobot"` -&gt; `"SixAxisRobot"`) * **`group`**: 固定为 `"DCP"` * **`category`**: 固定为 `"DCP"` * `description`: 如果 `组件元数据` 中提供了 `description`,则使用该值;否则默认为 `""`。 * `tags`: 如果 `组件元数据` 中提供了 `tags`,则使用该值;否则默认为 `""`。 * `keywords`: 如果 `组件元数据` 中提供了 `keywords`,则使用该值;否则默认为 `""`。 * `doc_url`: 如果 `组件元数据` 中提供了 `doc_url`,则使用该值;否则默认为 `""`。 * `devMode`: 固定为 `"proCode"`。 #### 2. **`npm` 对象构建** 根据 `package.json` 的内容,动态构建 `npm` 对象: * `package`: 从 `package.json` 中读取 `name` 字段。 * `exportName`: **必须**与顶层 `component` 字段的值保持一致。 * `version`: 从 `package.json` 中读取 `version` 字段。 * `script`: 基于 `package.json` 的信息,拼接成固定格式:`"http://192.168.0.212:4874/{package}@{version}/js/web-component.mjs"`。 * `destructuring`: 固定为 `true`。 * `npmrc`: 1. 从 `package.json` 的 `name` 字段提取 scope (例如 `@dcp/component-library` -&gt; `@dcp`)。 2. 从 `package.json` 的 `publishConfig.registry` 字段提取 registry URL (并移除末尾的 `/`)。 3. 拼接成 `"{scope}:registry={registry_url}"` 的格式。 #### 3. **`configure` 对象构建** 生成完整的 `configure` 对象,包含以下所有字段: **基础行为控制**: * `loop`: 固定为 `true`(支持循环渲染) * `condition`: 固定为 `true`(支持条件渲染) * `styles`: 固定为 `true`(支持样式配置) **组件类型标识**: * `isContainer`: 根据组件分析决定: - 如果组件模板中包含 `<slot>` 标签,设置为 `true` - 如果组件名称暗示容器用途(如 Layout、Container、Wrapper),设置为 `true` - 否则设置为 `false` * `isModal`: 固定为 `false`(除非组件明确是模态框) * `isPopper`: 固定为 `false`(除非组件明确是弹出框) * `isNullNode`: 固定为 `false` * `isLayout`: 根据组件用途判断,Layout 类组件设置为 `true`,否则为 `false` **嵌套规则**: * `nestingRule`: 对象包含以下字段,通常设置为默认值: - `childWhitelist`: `""`(允许的子组件白名单,通常为空) - `parentWhitelist`: `""`(允许的父组件白名单,通常为空) - `descendantBlacklist`: `""`(禁止的后代组件黑名单,通常为空) - `ancestorWhitelist`: `""`(允许的祖先组件白名单,通常为空) **编辑器配置**: * `rootSelector`: 固定为 `""` * `shortcuts.properties`: 识别出组件最核心、最常用的 1-3 个 props,填入此数组 * `contextMenu`: 对象包含: - `actions`: 默认为 `["copy", "remove", "insert", "updateAttr", "bindEevent"]` - `disable`: 默认为 `[]` **交互行为** (可选字段,根据组件类型添加): * `clickCapture`: 对于按钮类、交互类组件设置为 `true`,其他组件可省略或设置为 `false` * `framework`: 如果是第三方组件库保持原值,自定义组件设置为 `"Vue"` #### 4. **`schema.properties` (Props 分组映射)** 将 Vue 组件的所有 props 按逻辑功能分组,生成一个**分组数组**: **分组策略**: * **基础属性**: 核心功能相关的 props(如 name、size、type 等) * **样式属性**: 外观、颜色、尺寸相关的 props(如 width、height、backgroundColor、color 等) * **行为属性**: 交互、事件、状态相关的 props(如 disabled、loading、onClick 等) * **高级属性**: 可选的、专业配置项(如复杂对象配置、高级选项等) **每个分组对象必须包含**: * `name`: 分组标识符,使用数字字符串(如 `"0"`, `"1"`, `"2"`) * `label.zh_CN`: 分组的中文显示名称(如 `"基础属性"`, `"样式属性"`) * `description.zh_CN`: 分组的中文描述 * `content`: 该分组下的具体属性配置数组 **`content` 数组中的每个属性对象必须包含以下固定字段**: * `property`: Prop 的名称 * `label.text.zh_CN`: 中文标签 * `description`: 中文描述 * `required`: 根据 Vue Prop 中的 `required` 字段决定,默认为 `false` * `readOnly`: 固定为 `false` * `disabled`: **固定为 `false`** * `cols`: **固定为 `12`** * `labelPosition`: 固定为 `"left"` * `type`: Vue 类型转换为小写字符串 * `defaultValue`: Vue Prop 的默认值 * `widget`: 根据以下规则推断 **Widget 推断规则 (按优先级顺序)**: 1. **validator 函数解析 (最高优先级)**: - 如果 Prop 定义中存在 `validator` 函数,解析函数体中的选项数组 - 设置 `widget.component` 为 `"SelectConfigurator"` - 设置 `widget.props.options` 为解析出的选项数组 2. **属性名称模式匹配**: - 名称包含 `color` 或默认值以 `#` 开头 -&gt; `"ColorConfigurator"`,props: `{}` - 名称包含 `icon` -&gt; `"InputConfigurator"`,props: `{ "placeholder": "请输入图标名称" }` 3. **Vue 类型 + 语义推断**: - `Boolean` 类型: - 开关语义 (show*, enable*, is*) -&gt; `"SwitchConfigurator"`,props: `{}` - 选项语义 (disabled, loading, plain, round, circle) -&gt; `"CheckBoxConfigurator"`,props: `{}` - `Number` 类型 -&gt; `"NumberConfigurator"`,根据属性名称设置 props: - 尺寸类 (width, height, size): `{ "min": 50, "max": 2000, "step": 10 }` - 角度类 (rotate, angle): `{ "min": 0, "max": 360, "step": 1 }` - 比例类 (scale): `{ "min": 0.1, "max": 5, "step": 0.1 }` - 时间类 (duration, delay): `{ "min": 0, "max": 50, "step": 0.1 }` - 默认: `{ "step": 1 }` - `String` 类型 -&gt; `"InputConfigurator"`,props: `{ "placeholder": "请输入..." }` - `Object`/`Array` 类型 -&gt; `"CodeConfigurator"`,props: `{ "language": "json", "height": 150 }` 4. **智能类型分析**: - 如果 Prop 类型为 `Array as PropType<someinterface[]>`,在 `description` 中补充接口结构信息 #### 5. **`schema.events` (事件映射)** * 在组件 `<script>` 中搜索所有 `emit('event-name', ...)` 的调用。 * 每一个 `event-name` (kebab-case) 都对应 `events` 对象中的一个键。 * 该键的命名规则为 **`'on' +` 将 `event-name` 转换为首字母大写的驼峰式 (CamelCase)**。例如,`emit('menu-item-click')` 映射为 `onMenuItemClick`。 * 分析 `emit` 的参数,为该事件生成 `functionInfo.params` 数组。 #### 6. **`schema.slots` (插槽分析)** * 扫描组件的 `<template>` 部分,寻找所有 `<slot>` 标签。 * 对于每一个**具名插槽** (例如 `<slot name="menu-items">`),在 `schema.slots` 对象中为其添加一个条目。 * 该条目的键为插槽名 (`menu-items`),值为一个包含 `label.zh_CN` 和 `description.zh_CN` 的对象,用于描述该插槽的用途。 #### 7. **`snippets` (智能代码片段生成)** * 生成一个只包含**单个默认 Snippet** 的数组 `[]`。 * `name.zh_CN`, `icon`, `snippetName` 与顶层字段保持一致。 * `schema.props`: * **优先策略**: 在工作区中查找与组件同名的 `.stories.ts` 文件。如果找到,请使用其 `args` 对象作为 `props` 的数据来源。 * **备用策略**: 如果找不到 Storybook 文件,请不要简单地使用 `defaultValue`。应根据每个 Prop 的语境,创建一组有意义、更具代表性的示例值(例如,`username` 使用 `'Admin'` 而不是 `'User'`)。 --- ### 第三步:输出最终 JSON 请整合以上所有分析结果,生成最终的 JSON 文件。 

实战指南:从理论到实践

第一步:智能生成Schema

运用AI生成schema的过程就像与一位专业顾问的对话。让我们以Cursor编辑器为例,一步步地体验这个过程:

操作步骤:

  1. 打开组件项目:启动Cursor,进入你的Vue组件库项目
  2. 准备上下文材料:在聊天界面中添加以下关键文件:
    • 项目根目录的package.json
    • 目标组件的.vue源码文件
  3. 粘贴Prompt:将上文提供的完整Prompt复制到输入框
  4. 发起对话:按下回车键,等待AI的魔法发生

为什么选择Claude Sonnet 4?

经过测试对比,我发现Claude Sonnet 4在理解Vue组件结构和生成精准schema方面表现出色,像deepseek、qwen这些国内模型暂时无法:

  • 精准的类型推断:能够正确识别Props的TypeScript类型并转换为对应的widget配置
  • 智能的语义理解:根据属性名称自动推断合适的编辑器组件(颜色选择器、数字输入框等)
  • 结构化输出:生成的JSON格式规范、完整,直接可用

实际效果展示

设想我们有一个名为CustomButton的Vue组件:

<template> <button :class="buttonClass" :disabled="disabled" @click="handleClick" > <slot>{{ label }}</slot> </button> </template> <script setup lang="ts"> import { computed } from 'vue' interface Props { label?: string type?: 'primary' | 'secondary' | 'danger' size?: 'small' | 'medium' | 'large' disabled?: boolean loading?: boolean } const props = withDefaults(defineProps<Props>(), { label: '按钮', type: 'primary', size: 'medium', disabled: false, loading: false }) const emit = defineEmits<{ click: [event: MouseEvent] }>() const handleClick = (event: MouseEvent) => { if (!props.disabled && !props.loading) { emit('click', event) } } </script> 

通过AI处理后,会生成一个包含以下关键信息的schema:

  • Props分组:label、type、size被分类为“基础属性”,disabled、loading分类为“行为属性”
  • 组件类型:type属性自动配置为下拉选择器,并包含正确的选项
  • 事件映射:click事件被正确转换为onClick处理函数

第二步:添加物料

把上一步得到的json文件保存到TinyEngine项目根目录下的materials/components 文件夹下。

第三步:添加仓库

如果你没有添加过仓库配置,那么你需要在 项目根目录下的materials/packages.json 文件中添加你的仓库信息:

{ "name": "DCP组件库", "package": "@dcp/component-library", "version": "0.0.60", "script": "http://192.168.0.212:4874/@dcp/component-library@0.0.60/js/web-component.mjs", "destructuring": true, "npmrc": "@dcp:registry=http://192.168.0.212:4873" } 

第四步:构建物料

现在你可以直接在终端执行pnpm buildMaterials ,等终端不再有新的输出时,可以ctrl + c 退出脚本。

一切就绪,启动项目验收

至此,你可以pnpm serve:frontend 后访问项目来使用新增的组件了。

问题排查指南

在实际开发过程中,即使按照上述步骤操作,也可能遇到组件未正常显示的情况,这里为您提供了系统化的排查方法。

关键检查点一:组件获取机制

首先检查TinyEngine的组件获取机制是否正常工作。在以下位置添加调试信息:

文件位置: packages/canvas/render/src/material-function/material-getter.ts#L109

export const getComponent = (name) =&gt; { // 添加调试信息 console.log(`正在获取组件: ${name}:${getNative(name)}`) const result = Mapper[name] || getNative(name) || getBlock(name) || (isHTMLTag(name) ? name : getBlockComponent(name)) console.log(`获取结果:`, result) return result } 

ℹ️ 排查要点:对于引入的组件,getNative(name)应该返回非空值。如果返回undefined,说明组件没有被正确注册。

关键检查点二:动态导入机制

如果上一步检查发现问题,接下来排查动态导入机制。在以下位置添加调试代码:

文件位置: packages/canvas/common/src/utils.ts#L100

const dynamicImportComponentLib = async ({ pkg, script }: DynamicImportParams): Promise<any> =&gt; { console.log(`开始导入组件库: ${pkg}`) if (window.TinyComponentLibs[pkg]) { console.log(`组件库已存在缓存中: ${pkg}`) return window.TinyComponentLibs[pkg] } if (!script) { console.warn(`组件库 ${pkg} 缺少 script 配置`) return {} } const href = window.parent.location.href || location.href const scriptUrl = script.startsWith('.') ? new URL(script, href).href : script console.log(`动态导入组件库脚本: ${scriptUrl}`) if (!window.TinyComponentLibs[pkg]) { try { const modules = await import(/* @vite-ignore */ scriptUrl) console.log(`组件库导入成功:`, modules) window.TinyComponentLibs[pkg] = modules } catch (error) { console.error(`组件库导入失败: ${pkg}`, error) return {} } } return window.TinyComponentLibs[pkg] } 

常见问题及解决方案

📌 最常见问题:组件未正确导出

在我的实际经验中,这个问题出现频率最高。很多时候我们在组件库中开发了新组件,但忘记在入口文件中导出它。

解决方案

  1. 检查组件库的index.tsindex.js文件
  2. 确认目标组件已经被正确导出:
    export { default as YourComponent } from './YourComponent.vue' 

📌 脚本路径错误

检查packages.json中的script字段是否正确。常见错误包括:

  • 版本号不匹配
  • 域名或端口错误
  • 文件路径错误

通过以上系统化的排查步骤,绝大多数问题都能够得到快速解决。


如果您对AI开发感兴趣,欢迎关注我的公众号:观默视界

在这里,我会分享更多关于AI技术在实际开发中的实战经验和最新趋势。

关于OpenTiny

欢迎加入 OpenTiny 开源社区。添加微信小助手:opentiny-official 一起参与交流前端技术~

OpenTiny 官网<https: opentiny.design> OpenTiny 代码仓库<https: github.com opentiny> TinyVue 源码<https: github.com opentiny tiny-vue> TinyEngine 源码<https: github.com opentiny tiny-engine> 欢迎进入代码仓库 Star🌟TinyEngine、TinyVue、TinyNG、TinyCLI、TinyEditor~

如果你也想要共建,可以进入代码仓库,找到 good first issue标签,一起参与开源贡献~</https:></https:></https:></https:></any></someinterface[]></slot>

原文链接:https://my.oschina.net/u/6769809/blog/18683197
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章