引擎架构与生命周期
VTJ 引擎通过多层架构编排了一个复杂的低代码开发环境,将设计时和运行时的关注点分离,同时保持无缝的双向通信。该架构在统一的生态系统中实现了 AI 驱动的开发、可视化编辑和代码生成。
核心架构概述
引擎遵循分层微内核架构,在四个主要层级上实现了清晰的关注点分离:编排层、资源管理层、模拟层和渲染层。采用的设计模式包括依赖注入、事件驱动通信和基于提供者的资源分配。
Central Orchestrator"] State["State
UI State Management"] ToolRegistry["ToolRegistry
Extension Registry"] end subgraph Resource_Management_Layer [Resource Management Layer] Provider["Provider
Resource & Dependency Manager"] Assets["Assets
Project Asset Manager"] OpenApi["OpenApi
Remote API Service"] end subgraph Simulation_Layer [Simulation Layer] Simulator["Simulator
Isolated Iframe Environment"] SimulatorEnv["SimulatorEnv
Runtime Context"] end subgraph Rendering_Design_Layer [Rendering & Design Layer] Renderer["Renderer
Vue App Renderer"] Designer["Designer
Design Interaction Handler"] Context["Context
Execution Context"] end subgraph Data_Models [Data Models] ProjectModel["ProjectModel"] BlockModel["BlockModel"] HistoryModel["HistoryModel"] end Engine --> Provider Engine --> Simulator Engine --> Designer Engine --> State Engine --> ToolRegistry Engine --> Assets Engine --> OpenApi Engine --> ProjectModel Engine --> BlockModel Engine --> HistoryModel Simulator --> SimulatorEnv Simulator --> Renderer Renderer --> Context Designer --> SimulatorEnv Designer --> Context Provider --> SimulatorEnv Provider --> Context
Engine 类作为中央编排枢纽,管理从初始化到销毁的整个生命周期。它协调设计时交互(通过 Designer)、运行时渲染(通过 Renderer 和 Simulator)以及资源管理(通过 Provider 和 Assets)。状态管理(State)和扩展系统(ToolRegistry)提供了可插拔的自定义能力。
引擎组件与职责
Engine 核心
Engine 类(第 168-727 行)是主要的协调器,负责初始化和管理所有子系统。它维护对关键状态的反应式引用,包括当前项目、活动块文件、渲染上下文和历史管理器。
| 组件 | 类型 | 用途 | 生命周期 |
|---|---|---|---|
app |
`App | undefined` | 设计器 UI 的 Vue 应用实例 |
project |
`Ref<ProjectModel | null>` | 当前加载的项目模型 |
current |
`Ref<BlockModel | null>` | 当前正在编辑的块/页面 |
context |
`Ref<Context | null>` | 渲染执行上下文 |
history |
`Ref<HistoryModel | null>` | 撤销/重做管理 |
provider |
Provider |
资源和依赖管理器 | 在构造函数中创建 |
simulator |
Simulator |
隔离的渲染环境 | 在构造函数中创建 |
designer |
Designer |
设计交互处理器 | 在 simulator.render() 中创建 |
Engine 构造函数通过创建 Provider、Simulator、Assets 和其他子系统奠定基础,然后启动初始化序列,加载项目资源并渲染设计器界面。
Provider 系统
Provider 类(packages/renderer/src/provider/provider.ts 中的第 112-732 行)管理所有外部资源,包括依赖项、物料、API 和运行时全局变量。它根据 ContextMode 以不同的模式运行:
| 模式 | 描述 | 使用场景 |
|---|---|---|
Runtime |
生产运行时环境 | 运行生成的应用程序 |
Design |
带有模拟器的设计时 | 低代码设计器画布 |
Raw |
源代码模式 | Vue 源代码编辑 |
VNode |
虚拟节点渲染 | 高级渲染场景 |
Provider 的 load() 方法(第 205-249 行)执行关键的初始化序列:加载项目配置、根据模式加载依赖或资源、初始化模拟 API、设置路由并触发就绪事件。此方法充当项目元数据和可执行运行时之间的桥梁。
Simulator 环境
Simulator 类(packages/designer/src/framework/simulator.ts 中的第 77-404 行)创建一个隔离的 iframe 环境,用于托管实际的 Vue 应用程序渲染。这种隔离防止了样式冲突,并在设计器 UI 和渲染内容之间提供了清晰的分离。
模拟器环境(SimulatorEnv 接口,第 56-69 行)包括:
window: iframe 的 window 对象Vue: Vue 实例VueRouter: 路由实例library: 已加载的依赖库materials: 已加载的组件物料components: 可用的组件apis: API 模拟实现container: 用于挂载的 DOM 容器globals: 全局变量libraryLocaleMap: 本地化数据locales: 语言环境配置enhance: 可选的增强函数
init() 方法(第 98-172 行)设置 iframe、创建全局样式、初始化功能并与父窗口建立通信。此环境充当所有运行时代码执行的沙箱。
Renderer
Renderer 类(packages/designer/src/framework/renderer.ts 中的第 29-289 行)负责在模拟器环境中创建和管理 Vue 应用程序实例。其 install() 方法(第 48-120 行)使用插件、路由、全局属性和提供者配置 Vue 应用。
Renderer 与 Designer 维持双向关系,接收设计更改并将事件发送回引擎。它创建执行 DSL 指定组件和逻辑的实际渲染上下文。
Designer
Designer 类(packages/designer/src/framework/designer.ts 中的第 60-622 行)处理设计画布内的所有用户交互,包括拖放操作、选择、悬停状态和视觉反馈。它将事件监听器绑定到模拟器的内容窗口和文档。
Designer 解释鼠标事件,计算放置位置,通过 allowDrop()(第 569-610 行)验证允许的操作,并与引擎通信以更新底层模型。
引擎生命周期
引擎生命周期遵循从初始化到操作再到销毁的明确定义序列。此生命周期是事件驱动的,引擎响应各种模型和用户事件。
初始化阶段
初始化从 Engine 构造函数(第 194-244 行)开始:
- 依赖注入:使用提供的选项实例化 Provider、Simulator、Assets、Report 和 State
- 事件绑定 :
bindEvents()方法(第 346-359 行)为所有项目级事件注册处理器 - 项目加载 :
init()方法(第 249-288 行)调用provider.load()来初始化项目资源 - UI 渲染 :
render()方法(第 328-341 行)创建 Vue 应用程序并将其挂载到设计器容器 - 模拟器设置:Simulator 初始化 iframe 环境并为渲染做准备
提示 :初始化序列是异步的。
init()调用使用then()与render()链接,确保在 UI 渲染之前完全加载项目。这可以防止 UI 尝试访问未初始化资源的竞态条件。
运行时操作阶段
在运行时,引擎以事件驱动的方式运行,具有以下关键流程:
文件激活
当用户打开文件时,activeFile() 处理器(第 365-387 行)执行:
- 从服务加载 DSL
- 从 DSL 创建
BlockModel - 更新当前块引用
- 初始化历史跟踪
- 触发反应式更新
文件编辑
当设计器修改文件时,changeFile() 处理器(第 393-403 行)处理更改:
- 检查项目是否已锁定以防止并发编辑
- 将 BlockModel 转换为 DSL
- 通过服务保存 DSL
- 更新当前引用
- 如果启用了
autoHistory,则自动添加到历史记录
历史管理
引擎通过 HistoryModel 支持撤销/重做:
initHistory()(第 533-545 行):为当前块创建新的历史管理器saveHistory()(第 550-582 行):将 DSL 状态保存到历史堆栈loadHistory()(第 587-603 行):从历史记录中恢复先前的状态
这些方法由相应的事件 EVENT_HISTORY_CHANGE 和 EVENT_HISTORY_LOAD 触发。
销毁阶段
dispose() 方法(第 670-713 行)执行清理操作:
- 卸载设计器 Vue 应用程序
- 销毁模拟器和渲染器
- 从发射器中移除所有事件监听器
- 清除当前块和上下文引用
- 通过基类销毁执行任何额外的清理
正确的销毁可以防止内存泄漏,并确保在不再需要引擎时释放资源。
事件系统
引擎依赖于核心包中定义的综合事件系统。事件由模型和组件发出,处理器在 Engine 的 bindEvents() 方法中注册。
| 事件名称 | 处理器 | 触发条件 |
|---|---|---|
EVENT_PROJECT_CHANGE |
saveProject() |
项目元数据更改 |
EVENT_PROJECT_BLOCKS_CHANGE |
saveBlockFile() |
块文件添加/修改/删除 |
EVENT_PROJECT_PAGES_CHANGE |
saveBlockFile() |
页面文件添加/修改/删除 |
EVENT_PROJECT_DEPS_CHANGE |
saveMaterials() |
依赖项更改 |
EVENT_PROJECT_ACTIVED |
activeFile() |
文件打开/关闭 |
EVENT_PROJECT_PUBLISH |
publish() |
请求发布项目 |
EVENT_PROJECT_FILE_PUBLISH |
publishCurrent() |
请求发布当前文件 |
EVENT_BLOCK_CHANGE |
changeFile() |
块内容修改 |
EVENT_NODE_CHANGE |
changeCurrentFile() |
块内的节点修改 |
EVENT_HISTORY_CHANGE |
saveHistory() |
添加历史状态 |
EVENT_HISTORY_LOAD |
loadHistory() |
恢复历史状态 |
EVENT_PROJECT_GEN_SOURCE |
genSource() |
请求源代码生成 |
这种事件驱动的架构解耦了组件,并启用了灵活的扩展。自定义插件可以监听这些事件或发出自己的事件以扩展引擎功能。
状态管理
引擎通过多种反应式机制维护状态:
反应式状态
引擎状态使用 Vue 的 ref 和 shallowReactive API 进行管理:
project:包含 ProjectModel 的 Refcurrent:包含活动 BlockModel 的 Refcontext:包含渲染 Context 的 Refhistory:包含 HistoryModel 的 Refchanged:带有 Symbol 值的 Ref,用于触发更新
这些 refs 包装了 triggerRef(),以便在需要时强制反应性,特别是在异步操作之后。
Engine 状态(UI 偏好)
State 类(packages/designer/src/framework/state.ts 中的第 73-198 行)管理用户偏好和 UI 设置:
| 属性 | 类型 | 描述 | | ---------------- | ------- | ------------------------- | ------------------ | | outlineEnabled | boolean | 显示/隐藏设计视图指南 | | activeEvent | boolean | 启用/禁用设计视图事件处理 | | autoApply | boolean | 自动应用 AI 生成的 DSL | | autoHistory | boolean | 在更改时自动保存历史记录 | | llm | string | LLM | 当前选择的 AI 模型 | | LLMs | LLM[] | 可用的 AI 模型 | | tour | boolean | 显示/隐藏入职导览 | | dark | boolean | 启用深色模式 | | streaming | boolean | AI 生成正在进行中 |
状态更改会自动保存到本地存储,确保用户偏好跨会话持久化。
上下文和执行模型
Context 类(packages/renderer/src/render/context.ts 中的第 25-197 行)为 DSL 代码提供执行环境。它处理:
- 函数解析 :通过
__parseFunction()将 JSFunction 字符串转换为可执行函数 - 表达式解析 :通过
__parseExpression()计算 JSExpression 字符串 - 引用管理 :通过
__ref()和__getRefEl()处理组件引用 - 上下文克隆 :通过
__clone()为嵌套作用域创建隔离副本
上下文维护基于代理的执行模型,该模型拦截属性访问和方法调用,启用了 DSL 中定义的数据绑定和计算表达式等功能。
扩展点
引擎提供了多个用于自定义的扩展点:
插件系统
ToolRegistry 允许注册自定义工具和小组件。EngineOptions 中的 install 选项允许在创建设计器应用程序时执行自定义初始化逻辑。
Provider 适配器
EngineOptions 中的 adapter 选项(第 107 行)允许自定义提供者行为,包括 API 请求、组件解析和路由集成。
自定义小组件
Designer 框架通过小组件管理器支持自定义小组件。这些可以注册并集成到设计器界面中。
Setters
属性编辑器可以自定义,为特定的组件属性提供量身定制的编辑体验。
提示 :扩展应在引擎的
install回调期间注册自己。这确保所有核心子系统都已初始化,并提供对引擎实例的访问以便与其他系统集成。
集成模式
创建引擎实例
要创建引擎实例,您需要提供容器、服务和项目配置:
typescript
const engine = new Engine({
container: document.getElementById("designer-container"),
service: new MyFileService(),
project: {
id: "my-project",
name: "My Project",
platform: "web",
},
dependencies: {
vue: () => import("vue"),
"element-plus": () => import("element-plus"),
},
materials: {
"my-components": () => import("@my/ui"),
},
materialPath: "./node_modules/@vtj/ui",
globals: {
API_BASE: "https://api.example.com",
},
});
引擎异步初始化,并在 render() 方法完成后准备就绪。
使用引擎 Hook
在设计器内的 Vue 组件中,使用 useEngine() hook 访问引擎实例:
typescript
import { useEngine } from "@vtj/designer";
const engine = useEngine();
// Access engine properties
const currentBlock = engine.current.value;
const project = engine.project.value;
该 hook 使用 Vue 的 inject() API 来检索在应用程序根目录提供的引擎实例。
性能考虑
引擎架构包含了几种性能优化:
- 延迟加载:依赖项和物料通过动态导入异步加载
- 浅反应性 :引擎实例使用
shallowReactive以避免深度反应性开销 - 隔离渲染:模拟器在 iframe 中运行,防止设计器 UI 的样式重新计算
- 事件批处理 :可以通过
triggerRef()在触发反应式更新之前批处理多个更改 - 上下文缓存:渲染的组件被缓存以避免冗余重新创建
- 历史节流 :自动历史保存由
autoHistory标志控制,以防止过多的状态存储
这些优化确保即使处理复杂的项目和大型组件库,引擎也能保持响应。
引擎的模块化架构为理解低代码功能如何与标准 Vue 开发工作流集成提供了坚实的基础,从而在统一的环境中实现可视化编辑和基于代码的开发。
项目开源仓库: gitee.com/newgateway/...