渲染引擎
更新摘要
所做更改
- 新增了完整的NodeCache类实现说明,包括setNode/getNode/loadNode等API
- 增强了事件处理机制的详细说明,包括事件缓存策略的更新和插槽事件参数保护
- 完善了节点缓存管理系统,提供更精细的缓存控制和性能优化
- 更新了缓存系统章节,涵盖props、events和nodes的完整缓存策略
- 新增了NodeCache在节点渲染中的具体应用场景和实现细节
引言
本文件系统性梳理 VTJ 低代码渲染引擎的架构设计、渲染流程、组件渲染实现、DSL 到 Vue 组件的转换机制、事件与数据流、与设计器的协作关系、多端渲染与平台适配策略,并提供扩展指南与性能优化建议。本次更新重点介绍了渲染器架构的重大改进,包括新的缓存系统、增强的事件处理和性能优化策略,特别是NodeCache类的完整实现和节点缓存管理系统的增强。
项目结构
渲染引擎位于 packages/renderer,围绕 Provider(提供者)、渲染器(Renderer)与上下文(Context)三大核心构建,配合 @vtj/core 的 DSL 模型与 @vtj/utils 的工具能力,形成"DSL → 渲染器 → Vue 组件"的完整链路。新增的缓存系统和性能优化模块进一步提升了渲染效率。
graph TB
subgraph "渲染引擎"
RIndex["renderer/src/index.ts"]
RProvider["renderer/src/provider/provider.ts"]
RRender["renderer/src/render/block.ts"]
RContext["renderer/src/render/context.ts"]
RLoader["renderer/src/render/loader.ts"]
RCache["renderer/src/render/cache.ts"]
RNode["renderer/src/render/node.ts"]
RParser["renderer/src/utils/parser.ts"]
RServices["renderer/src/services/index.ts"]
RConst["renderer/src/constants.ts"]
RUtils["renderer/src/utils/index.ts"]
end
subgraph "核心模型"
CBlock["core/src/protocols/schemas/block.ts"]
CModels["core/src/models/index.ts"]
end
subgraph "设计器"
DIndex["designer/src/index.ts"]
end
RIndex --> RProvider
RIndex --> RRender
RIndex --> RContext
RIndex --> RLoader
RIndex --> RCache
RIndex --> RNode
RIndex --> RParser
RIndex --> RServices
RIndex --> RConst
RIndex --> RUtils
RRender --> RContext
RProvider --> RRender
RProvider --> RConst
RProvider --> RUtils
RLoader --> RCache
RLoader --> RRender
RNode --> RCache
RContext --> RParser
RRender --> CBlock
RProvider --> CBlock
DIndex --> RIndex
DIndex --> CModels
核心组件
- Provider:应用级提供者,负责项目加载、资源与依赖注入、路由初始化、全局配置、国际化、错误处理、DSL 渲染器创建与组件定义等。
- Renderer(DSL 渲染器):将 BlockSchema 转换为可执行的 Vue 组件,挂载 props/state/computed/methods/watch/inject/emits/lifecycle 等。
- Context:渲染上下文,桥接 Vue 实例与 DSL,提供表达式/函数解析、ref 管理、生命周期代理、设计态标记等能力。
- Loader:DSL 加载器,负责动态加载依赖的 DSL、插件组件和异步组件,支持缓存机制。
- Cache:节点缓存系统,提供 props、events 和 nodes 的缓存管理,包含完整的 NodeCache 类实现。
- Parser:表达式和函数解析器,支持安全的 JavaScript 代码执行。
- Services:服务层,提供内存存储、本地存储等服务支持。
架构总览
渲染引擎采用"Provider + DSL 渲染器 + 上下文 + 缓存系统"的四层架构:
- Provider 负责环境初始化、资源加载、路由注册、全局配置与国际化、错误处理、DSL 渲染器工厂。
- DSL 渲染器负责将 BlockSchema 转为 Vue 组件,统一处理 props、state、computed、methods、inject、dataSources、watch、emits、lifeCycles。
- Context 提供表达式/函数解析、ref 管理、设计态 DOM 标记、生命周期代理等。
- Loader 提供 DSL 加载和组件缓存,Queue 队列确保异步操作的有序执行。
- Cache 系统提供多层级缓存,包括 DSL 缓存、组件缓存和节点缓存,其中 NodeCache 类提供完整的节点级别缓存管理。
classDiagram
class Provider {
+mode
+globals
+modules
+adapter
+apis
+dependencies
+materials
+library
+service
+project
+components
+urlDslCaches
+load(project)
+createDslRenderer(dsl, opts)
+getRenderComponent(id, output?)
+defineUrlSchemaComponent(url, name?)
+definePluginComponent(from)
}
class Context {
+__mode
+__instance
+state
+props
+$props
+$refs
+$emit
+setup(attrs, Vue)
+__parseFunction(code)
+__parseExpression(code)
+__ref(id?, ref?)
+__refCaches
}
class Renderer {
+renderer
+context
}
class Loader {
+__loaders__
+__caches__
+__plugins__
+createLoader(opts)
+getPlugin(from, global)
+clearLoaderCache()
}
class NodeCache {
+__props : Record
+__events : Record
+__nodes : Record
+setProps(id, value)
+getProps(id)
+loadProps(key, value)
+setEvents(id, value)
+getEvents(id)
+loadEvents(key, value)
+setNode(id, value)
+getNode(id)
+loadNode(key, value)
+isEqual(value, other)
+clear()
}
class Cache {
+__props
+__events
+__nodes
+setProps(id, value)
+getProps(id)
+loadProps(key, value)
+setEvents(id, value)
+getEvents(id)
+loadEvents(key, value)
+setNode(id, value)
+getNode(id)
+loadNode(key, value)
+clear()
}
Provider --> Renderer : "创建 DSL 渲染器"
Renderer --> Context : "持有上下文"
Loader --> Renderer : "缓存组件"
Cache --> Loader : "节点缓存"
NodeCache --> Cache : "继承"
详细组件分析
Provider:应用提供者与渲染器工厂
职责概览
- 项目加载与初始化:根据运行模式加载依赖/资源、Mock、API、路由。
- 资源与依赖管理:解析依赖、按需加载 CSS/JS、物料组件注册、第三方库插件安装。
- 路由集成:支持静态路由与动态路由,支持 uniapp 平台差异。
- 全局配置与国际化:运行时注入全局变量、国际化初始化。
- 错误处理:统一错误处理与通知。
- DSL 渲染器工厂:合并默认选项与自定义选项,创建渲染器与加载器。
- 组件定义:支持基于 URL 与插件的异步组件定义。
- DSL 缓存:维护 URL DSL 缓存,提升远程 DSL 加载性能。
关键流程(加载项目)
sequenceDiagram
participant App as "应用"
participant Prov as "Provider"
participant Svc as "Service"
participant Dep as "依赖/资源"
participant Router as "路由"
App->>Prov : new Provider(options)
App->>Prov : load(project)
Prov->>Svc : init(project)
Svc-->>Prov : ProjectSchema
Prov->>Dep : loadDependencies()/loadAssets()
Prov->>Prov : initMock()/createSchemaApis()
Prov->>Router : initRouter()
Prov-->>App : triggerReady()
DSL 渲染器:从 BlockSchema 到 Vue 组件
职责概览
- 将 BlockSchema 转换为 Vue 组件,挂载 props、state、computed、methods、inject、dataSources、watch、emits、lifeCycles。
- 支持样式作用域注入(adoptedStyleSheets)。
- 通过 Context 统一解析表达式与函数,支持运行时 transform 缓存。
- 集成 Loader 提供的缓存机制,提升组件渲染性能。
渲染主流程
sequenceDiagram
participant Prov as "Provider"
participant Loader as "BlockLoader"
participant Ctx as "Context"
participant Comp as "Vue 组件(renderer)"
Prov->>Loader : createLoader(getDsl/getDslByUrl)
Prov->>Ctx : new Context({mode, dsl, attrs})
Prov->>Comp : createRenderer({dsl, loader, components, libs, apis})
Comp->>Ctx : setup(props) -> state/computed/methods/inject/dataSources
Comp->>Ctx : setWatches()
Comp-->>Prov : 返回 renderer + context
Context:渲染上下文与表达式/函数解析
职责概览
- 挂载 Vue 实例属性(emit/$nextTick 等),在 onMounted 后重建代理。
- 表达式与函数解析:根据运行模式选择直接解析或使用 transform 缓存。
- ref 管理:支持 id/ref 的 DOM/组件引用收集,设计态标记 draggable。
- 生命周期代理:延迟执行 lifeCycles,保证渲染时机正确。
- 上下文克隆:支持浅拷贝上下文以派生子上下文。
- 缓存支持:集成 __refCaches 提升 ref 函数的性能。
表达式/函数解析流程
flowchart TD
Start(["进入解析"]) --> Mode{"运行模式"}
Mode --> |Runtime| UseTransform["使用 transform 缓存或 id 映射"]
Mode --> |其他| DirectParse["直接解析"]
UseTransform --> ParseFunc["parseFunction/parseExpression"]
DirectParse --> ParseFunc
ParseFunc --> End(["返回可执行函数"])
缓存系统
DSL 缓存机制
Provider 维护了 urlDslCaches 缓存,用于存储远程 DSL 配置,避免重复网络请求:
flowchart TD
URL["DSL URL"] --> Check{"缓存是否存在?"}
Check --> |是| Return["返回缓存的 DSL"]
Check --> |否| Request["发起网络请求"]
Request --> Store["存储到缓存"]
Store --> Return
组件缓存系统
Loader 提供了多层级缓存机制,包括 DSL 缓存和组件缓存:
flowchart TD
Load["加载组件"] --> FromType{"from.type 类型"}
FromType --> |Schema| SchemaCache["DSL 缓存 (__loaders__)"]
FromType --> |UrlSchema| UrlCache["URL 缓存 (__loaders__)"]
FromType --> |Plugin| PluginCache["插件缓存 (__loaders__)"]
SchemaCache --> ComponentCache["组件缓存 (__caches__)"]
UrlCache --> ComponentCache
PluginCache --> ComponentCache
ComponentCache --> AsyncComp["Vue.defineAsyncComponent"]
节点缓存管理
新增的 NodeCache 类提供了完整的节点级别缓存管理,包含以下核心功能:
NodeCache 类实现
NodeCache 是一个专门用于节点缓存管理的类,提供以下核心方法:
classDiagram
class NodeCache {
+__props : Record<string, any>
+__events : Record<string, any>
+__nodes : Record<string, any>
+constructor()
+setProps(id : string, value : any) void
+getProps(id : string) any
+loadProps(key : string, value : any) any
+setEvents(id : string, value : any) void
+getEvents(id : string) any
+loadEvents(key : string, value : any) any
+setNode(id : string, value : any) void
+getNode(id : string) any
+loadNode(key : string, value : any) any
+isEqual(value : any, other : any) boolean
+clear() void
}
节点缓存工作原理
NodeCache 在节点渲染过程中的具体应用:
sequenceDiagram
participant NodeRender as "nodeRender"
participant NodeCache as "NodeCache"
participant Vue as "Vue"
NodeRender->>NodeCache : loadNode(key, cache)
NodeCache->>NodeCache : getNode(key)
alt 缓存存在且相等
NodeCache-->>NodeRender : 返回缓存
else 缓存不存在或不相等
NodeCache->>NodeCache : setNode(key, cache)
NodeCache-->>NodeRender : 返回新缓存
end
NodeRender->>Vue : createVNode(component, cache, slots)
缓存策略详解
NodeCache 提供了三种类型的缓存管理:
- Props 缓存:缓存节点的属性配置
- Events 缓存:缓存节点的事件处理函数(当前版本禁用)
- Nodes 缓存:缓存完整的节点配置对象
每个缓存类型都提供了对应的 CRUD 操作方法,确保缓存的一致性和有效性。
事件处理机制
事件缓存策略
当前版本中,事件缓存被暂时禁用以避免插槽事件参数丢失的问题。在 NodeCache 中,事件缓存方法被注释掉:
setEvents(_id: string, _value: any) {
// todo: 记录事件缓存会导致插槽的事件参数丢失,先取消缓存
// this.__events[id] = value;
}
这种设计决策是为了确保插槽事件的参数传递完整性,虽然可能略微影响性能,但保证了功能的正确性。
异步组件事件处理
Loader 通过 Vue.defineAsyncComponent 处理异步组件的事件绑定,确保组件加载完成后再进行事件处理。
生命周期事件优化
渲染器中的生命周期事件通过 delay(0) 确保在微任务队列中执行,避免与渲染时机冲突。
性能优化策略
缓存优化
- DSL 缓存:Provider 的 urlDslCaches 避免重复网络请求
- 组件缓存:Loader 的 loaders 和 caches 提供多层级缓存
- 节点缓存:NodeCache 管理 props、events 和 nodes 的缓存,通过 isEqual 方法进行深度比较
- ref 缓存:Context 的 __refCaches 提升 ref 函数性能
异步队列处理
Loader 使用 Queue 确保异步操作的有序执行,避免并发问题:
flowchart LR
Queue["Queue 队列"] --> Add["add(id, promise)"]
Add --> Execute["按顺序执行"]
Execute --> Result["返回结果"]
内存管理
- 自动清理:clearLoaderCache() 清理所有缓存和队列,包括 NodeCache.clear()
- 条件缓存:事件缓存根据需求动态启用/禁用
- 去重机制:__getRefEl() 方法确保 ref 引用的唯一性
- 深度比较:isEqual 方法确保缓存的有效性
服务层架构
服务类型
渲染引擎提供了多种服务支持:
graph TB
Services["Services 层"]
Base["Base Service"]
Memory["Memory Service"]
Local["Local Storage Service"]
Storage["Storage Service"]
Queue["Queue Service"]
Services --> Base
Services --> Memory
Services --> Local
Services --> Storage
Services --> Queue
内存存储服务
Memory Service 提供基于内存的临时存储,适用于运行时数据缓存。
本地存储服务
Local Storage Service 提供持久化存储,支持跨会话的数据保存。
存储服务抽象
Storage Service 抽象了不同存储方式的统一接口,便于切换存储后端。
依赖分析
- 渲染引擎依赖 @vtj/core 提供的 DSL 模型与协议,依赖 @vtj/utils 提供的工具函数(如解析、请求、防抖、样式注入等)。
- 设计器依赖 @vtj/renderer 与 @vtj/core,同时引入 UI、图标、Vue DevTools 等生态依赖。
- 核心包 @vtj/core 作为 DSL 与协议的承载层,提供基础模型与协议定义。
- 新增的缓存系统依赖 @vtj/utils 的 Queue 和 cloneDeep 工具。
graph LR
Renderer["@vtj/renderer"] --> Core["@vtj/core"]
Renderer --> Utils["@vtj/utils"]
Renderer --> Services["@vtj/renderer/services"]
Designer["@vtj/designer"] --> Renderer
Designer --> Core
Designer --> UI["@vtj/ui"]
Designer --> Icons["@vtj/icons"]
故障排查指南
- 组件渲染错误:Provider 在设计态下设置统一错误处理器,捕获组件渲染错误并通过适配器通知。
- 版本不一致:开发态下校验组件源码版本与运行时版本,不一致时通过适配器发出警告。
- 资源加载失败:检查依赖与物料路径配置,确认 CSS/JS 资源可访问。
- 路由异常:确认是否为 uniapp 平台,以及静态路由开关与路由追加配置。
- 缓存问题:使用 clearLoaderCache() 清理所有缓存,重新加载组件。
- 性能问题:检查缓存命中率,监控内存使用情况,必要时调整缓存策略。
- 事件参数丢失:如果遇到插槽事件参数丢失问题,检查事件缓存策略。
结论
VTJ 渲染引擎以 Provider 为核心,结合 DSL 渲染器、Context 和全新的缓存系统,实现了从 DSL 到可执行 Vue 组件的完整闭环。通过清晰的职责划分、完善的错误处理与平台适配、可扩展的组件定义机制,以及新增的缓存系统和性能优化策略,既能满足快速搭建页面的需求,也为二次开发与性能优化提供了坚实基础。
NodeCache 类的引入进一步增强了渲染引擎的性能表现,通过精细化的节点缓存管理,有效减少了重复计算和内存占用。事件缓存策略的更新确保了功能的正确性,而异步队列和内存管理机制则保证了系统的稳定性和可靠性。
附录
渲染器扩展指南
- 自定义渲染组件
- 基于 URL 的异步组件:使用 Provider 的 defineUrlSchemaComponent,按 URL 获取 DSL 并创建渲染器。
- 基于插件的异步组件:使用 definePluginComponent,按插件来源动态加载组件。
- 原始 Vue 组件:在 Raw 模式下,可从模块缓存加载 .vue 文件作为渲染组件。
- 自定义渲染器
- 通过 createDslRenderer 合并默认选项与自定义选项,创建渲染器实例。
- 在渲染器中扩展 props/state/computed/methods/inject/dataSources/watch/emits/lifeCycles。
- 事件与生命周期
- 在 DSL 中定义 emits 与 lifeCycles,渲染器自动处理;在 Context 中确保生命周期在正确时机执行。
- 缓存管理
- 使用 clearLoaderCache() 清理所有缓存,包括 NodeCache
- 监控缓存命中率,优化缓存策略
- 根据场景启用/禁用特定缓存类型
- 利用 NodeCache 的 isEqual 方法进行深度比较,确保缓存有效性
渲染性能调优技巧
- 合理使用缓存:利用 DSL 缓存、组件缓存和节点缓存减少重复计算。
- 优化缓存策略:根据使用频率调整缓存时间,避免内存泄漏。
- 控制依赖数量:开发环境按需加载物料与库,生产环境跳过物料描述文件。
- 避免不必要的重渲染:合理设置 watch 的 deep/immediate,避免大对象深监听。
- 使用静态路由:在页面较多时启用静态路由,减少动态路由匹配开销。
- 样式作用域:按组件注入样式作用域,避免全局样式影响。
- 监控内存使用:定期清理缓存,避免内存泄漏。
- 异步队列管理:合理使用 Queue 确保异步操作有序执行。
- 节点缓存优化:利用 NodeCache 的缓存机制,减少节点渲染开销。
- 事件处理优化:根据需求启用/禁用事件缓存,平衡性能与功能正确性。
参考资料
VTJ.PRO VTJ.PRO 是一个开源的 AI 低代码引擎,专注解决 “低代码生成代码不可控、难维护” 的痛点。更多信息请访问:
- 📘 官方文档:vtj.pro/
- 🌐 在线平台:app.vtj.pro/
- 📦 开源仓库:gitee.com/newgateway/…