Provider API 参考
Provider API 是 VTJ 中数据持久化、代码生成和跨平台操作的基础抽象层。这份详尽的参考文档介绍了 Service 抽象类、其协议接口、Schema 定义以及使用自定义后端扩展 Provider 系统的实现模式。
架构概览
Provider API 架构遵循 协议优先设计,所有数据操作都通过标准化的 Service 接口进行。这种抽象实现了可插拔的存储后端(本地文件、云服务、数据库),同时在整个 VTJ 生态系统中保持一致的 API 契约。
Service 抽象类
Service 抽象类定义了 Provider 实现的完整契约,位于 packages/core/src/protocols/service.ts。所有方法均返回 Promises 以支持跨不同存储后端的异步操作。
项目管理 API
| 方法 | 目的 | 参数 | 返回类型 |
|---|---|---|---|
getExtension() |
获取设计器扩展配置 | - | `Promise<VTJConfig |
init() |
使用 Schema 初始化项目 | project: Partial<ProjectSchema>, isInit?: boolean |
Promise<ProjectSchema> |
saveProject() |
持久化项目 Schema | project: ProjectSchema, type?: string |
Promise<boolean> |
saveMaterials() |
保存物料描述 | project: ProjectSchema, materials: Map<string, MaterialDescription> |
Promise<boolean> |
publish() |
完整项目代码生成 | project: ProjectSchema |
Promise<boolean> |
getExtension 方法检索包括路由模式、基础路径、平台设置和身份验证选项在内的 VTJ 运行时配置,定义见 VTJConfig 接口。init 方法通过 isInit 标志支持新项目创建和现有项目加载。
文件管理 API
| 方法 | 目的 | 参数 | 返回类型 |
|---|---|---|---|
saveFile() |
持久化页面或区块文件 | file: BlockSchema, project?: ProjectSchema |
Promise<boolean> |
getFile() |
获取文件 Schema | id: string, project?: ProjectSchema |
Promise<BlockSchema> |
removeFile() |
从项目中删除文件 | id: string, project?: ProjectSchema |
Promise<boolean> |
publishFile() |
为单个文件生成代码 | `project: ProjectSchema, file: PageFile | BlockFile` |
文件操作使用 BlockSchema,它定义了完整的 DSL 结构,包括组件树 (nodes)、状态管理 (state, computed, watch)、生命周期钩子 (lifeCycles)、方法、样式和数据源。文件通过 PageFile 和 BlockFile 接口分类为 PageFile 或 BlockFile。
历史记录管理 API
| 方法 | 目的 | 参数 | 返回类型 |
|---|---|---|---|
saveHistory() |
持久化文件历史记录 | history: HistorySchema, project?: ProjectSchema |
Promise<boolean> |
getHistory() |
获取文件历史记录 | id: string, project?: ProjectSchema |
Promise<HistorySchema> |
removeHistory() |
删除文件历史记录 | id: string, project?: ProjectSchema |
Promise<boolean> |
saveHistoryItem() |
添加历史版本 | fId: string, item: HistoryItem, project?: ProjectSchema |
Promise<boolean> |
getHistoryItem() |
获取特定版本 | fId: string, id: string, project?: ProjectSchema |
Promise<HistoryItem> |
removeHistoryItem() |
删除历史版本 | fId: string, ids: string[], project?: ProjectSchema |
Promise<boolean> |
历史记录跟踪基于 HistorySchema,它将文件 ID 与 HistoryItem 记录数组关联,每条记录包含 DSL 快照、时间戳(隐式在 Schema 结构中)、标签和可选备注。
代码生成 API
| 方法 | 目的 | 参数 | 返回类型 |
|---|---|---|---|
genVueContent() |
将 DSL 转换为 Vue 源代码 | project: ProjectSchema, dsl: BlockSchema |
Promise<string> |
parseVue() |
解析 Vue 源代码为 DSL | project: ProjectSchema, options: ParseVueOptions |
Promise<BlockSchema> |
genSource() |
生成完整项目归档 | project: ProjectSchema |
Promise<string> |
createRawPage() |
创建源码模式页面 | file: PageFile, project?: ProjectSchema |
Promise<boolean> |
removeRawPage() |
删除源码模式页面 | id: string, project?: ProjectSchema |
Promise<boolean> |
genVueContent 方法执行 DSL 到代码的转换,如 DSL 转 Vue 代码生成 中所述。parseVue 方法接受 ParseVueOptions,其中包含文件 ID、名称和源代码内容,实现了 Vue 源代码转 DSL 解析 中描述的双向转换。
静态文件管理 API
| 方法 | 目的 | 参数 | 返回类型 |
|---|---|---|---|
uploadStaticFile() |
上传资源到项目 | file: File, projectId: string |
`Promise<StaticFileInfo |
getStaticFiles() |
列出项目静态文件 | projectId: string |
Promise<StaticFileInfo[]> |
removeStaticFile() |
删除静态资源 | name: string, projectId: string, file?: StaticFileInfo |
Promise<boolean> |
clearStaticFiles() |
删除所有静态文件 | projectId: string |
Promise<boolean> |
静态文件使用 StaticFileInfo 进行跟踪,其中包含可选的 ID、文件名和必需的文件路径属性。这些方法支持图片、样式表和其他资源的项目级资源管理。
插件物料 API
| 方法 | 目的 | 参数 | 返回类型 |
|---|---|---|---|
getPluginMaterial() |
获取插件组件描述 | from: NodeFromPlugin |
`Promise<MaterialDescription |
此方法支持从插件源动态加载物料,支持 NodeFromPlugin 接口,该接口定义了包含 URL 数组和可选库导出名称的插件类型。
核心 Schema 定义
Project Schema
ProjectSchema 接口代表完整的项目配置:
typescript
interface ProjectSchema {
id?: string;
name: string;
description?: string;
platform?: PlatformType;
pages?: PageFile[];
blocks?: BlockFile[];
homepage?: string;
dependencies?: Dependencie[];
apis?: ApiSchema[];
meta?: MetaSchema[];
config?: ProjectConfig;
uniConfig?: UniConfig;
globals?: GlobalConfig;
i18n?: I18nConfig;
env?: EnvConfig[];
__VTJ_PROJECT__?: boolean;
__VERSION__?: string;
__BASE_PATH__?: string;
__UID__?: string;
}
关键配置部分:
pages:PageFile对象数组,定义页面路由、布局和元数据blocks:BlockFile对象数组,用于可复用组件定义dependencies:Dependencie数组,指定带有平台目标的 npm 包globals:GlobalConfig,用于全局样式、Store、访问控制和 HTTP 拦截器i18n:I18nConfig,用于包含区域设置和消息定义的国际化
Block Schema
BlockSchema 代表核心 DSL 结构:
typescript
interface BlockSchema {
id?: string;
name: string;
locked?: boolean;
inject?: BlockInject[];
state?: BlockState;
lifeCycles?: Record<string, JSFunction>;
methods?: Record<string, JSFunction>;
computed?: Record<string, JSFunction>;
watch?: BlockWatch[];
css?: string;
props?: Array<string | BlockProp>;
emits?: Array<string | BlockEmit>;
expose?: string[];
slots?: Array<string | BlockSlot>;
nodes?: NodeSchema[];
dataSources?: Record<string, DataSourceSchema>;
transform?: Record<string, string>;
}
核心组件:
nodes:NodeSchema数组,定义组件树结构state:BlockState映射响应式数据值methods:将方法名称映射到JSFunction实现的映射computed:将计算属性名称映射到JSFunction表达式的映射watch:BlockWatch数组,用于响应式数据观察lifeCycles:生命周期钩子(onMounted、onBeforeUnmount 等),映射到JSFunctiondataSources:用于 API 调用和数据转换的DataSourceSchema映射
💡
transform属性缓存 Babel 转译后的代码,用于运行时优化,避免在渲染周期中重复编译方法和计算函数字符串。
Node Schema
NodeSchema 定义 DSL 树中的单个组件节点:
typescript
interface NodeSchema {
id?: string;
name: string;
from?: NodeFrom;
locked?: boolean;
invisible?: boolean;
props?: NodeProps;
events?: NodeEvents;
directives?: NodeDirective[];
children?: NodeChildren;
slot?: string | NodeSlot;
}
关键属性:
name:组件名称(例如 "el-button"、"a-input")from:NodeFrom,指定来源类型(包名、Schema 引用、URL 或插件)props:NodeProps,包含组件属性,包括key、ref、style和class等特殊键events:NodeEvents,将事件名称映射到NodeEvent处理程序directives:NodeDirective数组,用于 v-if、v-for、v-model 等children:嵌套节点数组或表达式slot:插槽放置定位,带有可选的作用域参数
Data Source Schema
DataSourceSchema 支持声明式数据获取:
typescript
interface DataSourceSchema {
type: DataSourceType;
ref?: string;
name: string;
label?: string;
transform?: JSFunction;
test?: JSFunction;
mockTemplate?: JSFunction;
}
数据源类型:
api:引用项目级ApiSchema,包含方法、URL、Headers 和 Mock 设置cube:配置的查询集成(特定于后端)meta:配置的元数据查询集成mock:使用mockTemplate的纯 Mock 数据
transform 属性允许数据处理函数将原始 API 响应转换为 UI 就绪格式,而 test 提供开发时的测试功能。
Material Schema
物料描述通过 MaterialDescription 接口定义可用组件:
typescript
interface MaterialDescription {
name: string;
alias?: string;
parent?: string;
icon?: string;
label?: string;
doc?: string;
categoryId?: number | string;
props?: MaterialProp[];
events?: Array<string | MaterialEvent>;
slots?: Array<string | MaterialSlot>;
snippet?: Partial<NodeSchema>;
parentIncludes?: boolean | string[];
childIncludes?: boolean | string[];
hidden?: boolean;
from?: NodeFrom;
id?: string;
package?: string;
}
组件注册:
name:设计器引用的唯一组件标识符alias:原始库导出名称(例如 ant-design-vue 中的 "Button")parent:子组件的父组件(例如 "Button.Group" 的 "Button")snippet:组件拖拽到画布时的初始 DSL 结构parentIncludes:限制放置到特定的父组件中childIncludes:限制允许的子组件类型
属性通过 MaterialProp 定义,包含类型规范、默认值和设计器属性面板的 Setter 配置。
共享协议类型
表达式类型
VTJ 通过专用接口区分静态值和运行时可执行代码:
typescript
interface JSExpression {
type: "JSExpression";
id?: string;
value: string;
}
interface JSFunction {
type: "JSFunction";
id?: string;
value: string;
}
这些接口使 DSL 结构能够区分字面量值和需要运行时求值的代码,支持 DSL Schema 和数据模型 中描述的声明式数据绑定模式。
VTJ Configuration
VTJConfig 接口配置运行时行为:
typescript
interface VTJConfig {
enhance?: boolean | EnhanceConfig;
extension?: ExtensionConfig;
history?: "hash" | "web";
base?: string;
pageRouteName?: string;
pageBasePath?: string;
__BASE_PATH__?: string;
remote?: string;
auth?: string | (() => Promise<any>);
checkVersion?: boolean;
platform?: PlatformType;
access?: Record<string, any>;
__ACCESS__?: Record<string, any>;
}
运行时能力:
extension:ExtensionConfig,用于外部 UMD 库注入history:路由器模式选择(hash 或 web history)auth:身份验证函数或端点access:权限控制配置remote:云 Provider 场景的远程服务主机
本地服务实现
packages/local/src/service.ts 中的本地服务提供了基于文件系统存储的参考实现,演示了正确的 Provider 扩展模式。
初始化模式
typescript
export async function init(body: any, opts: DevToolsOptions) {
// 1. 加载或创建项目 Schema
// 2. 初始化存储库层
// 3. 设置特定于平台的配置
// 4. 返回已初始化的 ProjectSchema
}
该实现使用来自 packages/local/src/repository/ 的存储库模式层来处理不同的文件类型:
| 存储库 | 目的 | 处理的文件 |
|---|---|---|
JsonRepository |
DSL Schema 持久化 | .json 项目、页面、区块文件 |
VueRepository |
源代码文件 | .vue 组件文件 |
StaticRepository |
资产管理 | 图片、字体、样式表 |
PluginRepository |
插件物料加载 | 远程插件描述符 |
UniRepository |
UniApp 配置 | manifest.json、pages.json |
💡 存储库模式使得在不修改服务逻辑的情况下切换存储后端成为可能。对于云 Provider,请用基于 HTTP 的数据访问层替换 JSON 存储库,同时保持相同的服务方法签名。
扩展 Provider 系统
自定义 Provider 实现
要创建自定义 Provider,请扩展 Service 抽象类:
typescript
import { Service } from "@vtj/core";
import type {
ProjectSchema,
BlockSchema,
VTJConfig,
HistorySchema,
HistoryItem,
MaterialDescription,
PageFile,
BlockFile,
} from "@vtj/core";
export class CloudProvider extends Service {
private client: HttpClient;
constructor(config: CloudConfig) {
super();
this.client = new HttpClient(config);
}
async getExtension(): Promise<VTJConfig | undefined> {
const response = await this.client.get("/api/config");
return response.data;
}
async init(project: Partial<ProjectSchema>): Promise<ProjectSchema> {
const response = await this.client.post("/api/projects/init", project);
return response.data;
}
async saveProject(project: ProjectSchema): Promise<boolean> {
await this.client.put(`/api/projects/${project.id}`, project);
return true;
}
// 实现所有抽象方法...
}
Provider 注册
向设计器或渲染器注册自定义 Provider:
typescript
import { CloudProvider } from "./providers/cloud-provider";
import { Designer } from "@vtj/designer";
const provider = new CloudProvider({
baseUrl: "https://api.vtj.example.com",
apiKey: process.env.API_KEY,
});
const designer = new Designer({
provider: provider,
materials: defaultMaterials,
});
详细的 Provider 扩展模式在 扩展 Provider 系统 中有介绍。
异步错误处理
Provider 方法应实现健壮的错误处理:
typescript
async getFile(id: string, project?: ProjectSchema): Promise<BlockSchema> {
try {
const response = await this.client.get(`/api/files/${id}`);
return BlockModel.create(response.data);
} catch (error) {
if (error.status === 404) {
throw new Error(`File not found: ${id}`);
}
throw new Error(`Failed to retrieve file: ${error.message}`);
}
}
服务抽象类定义了契约,但并未规定错误处理策略------实现应针对其特定用例选择适当的错误传播模式。
Provider 集成点
设计器集成
设计器使用 Provider 进行:
- 项目加载 :启动时
init()检索完整项目 Schema - 自动保存 :设计器更改时触发
saveFile(),带有防抖功能 - 历史记录跟踪 :手动保存时
saveHistoryItem()捕获快照版本 - 代码预览 :
genVueContent()为预览面板生成实时 Vue 代码 - 物料加载 :
getPluginMaterial()获取动态组件描述
运行时集成
渲染器通过以下方式使用 Provider API:
- 配置 :
getExtension()提供运行时 VTJConfig 设置 - 动态加载:延迟加载的区块和页面的文件获取
- 热更新:与 HMR 集成,用于开发时 Schema 更改
类型安全注意事项
Provider API 广泛利用 TypeScript 的类型系统:
- 泛型约束:针对 Schema 接口类型的存储库实现
- 可辨识联合 :
NodeFrom类型使用可辨识联合来保证来源类型安全 - 字面量类型 :
DataSourceType、ApiMethod、PlatformType使用字符串字面量联合进行编译时验证
扩展 Provider 时,请通过以下方式保持类型安全:
- 从
@vtj/core协议导入所有类型 - 使用
typeof运算符进行 Schema 引用 - 使用正确的参数和返回类型实现所有抽象方法
- 对照
MaterialDescription对插件物料导入进行类型检查
跨平台支持
Provider 必须处理特定于平台的差异:
| 平台 | 配置 | 代码生成 |
|---|---|---|
| Web | 带有 axios、路由守卫的 GlobalConfig |
标准 Vue 3 语法 |
| H5 | 移动端优化的 GlobalConfig |
H5 特定的 CSS 和 API |
| UniApp | 带有 manifest、pages JSON 的 UniConfig |
UniApp 组件语法和 API |
PlatformType 联合类型 ('web' \| 'h5' \| 'uniapp') 驱动 genVueContent 中的条件逻辑和特定于平台的存储库操作,如 packages/local/src/launch/ 中所实现。
相关 API 文档
Provider API 与其他核心系统协同工作:
- Engine API Reference:引擎生命周期管理和设计器核心 API
- Renderer API Reference:运行时渲染和组件组合 API
- Project Structure and File Organization:对应 Schema 结构的物理文件布局
要全面了解 VTJ 的架构模式,请查看 架构概览,它解释了 Provider 抽象层如何实现系统的可扩展性和平台可移植性。
参考资料
- 官方文档:vtj.pro/
- 在线平台:app.vtj.pro/
- 开源仓库:gitee.com/newgateway/...