火花语音盒(崩铁火花
25.0MB · 2026-03-26
Provider API 是 VTJ 中数据持久化、代码生成和跨平台操作的基础抽象层。这份详尽的参考文档介绍了 Service 抽象类、其协议接口、Schema 定义以及使用自定义后端扩展 Provider 系统的实现模式。
Provider API 架构遵循 协议优先设计,所有数据操作都通过标准化的 Service 接口进行。这种抽象实现了可插拔的存储后端(本地文件、云服务、数据库),同时在整个 VTJ 生态系统中保持一致的 API 契约。
flowchart TB
subgraph Application["VTJ Applications"]
Designer["Designer IDE"]
Runtime["Renderer Runtime"]
end
subgraph CoreProtocol["@vtj/core - Protocols"]
Service["Service Abstract Class"]
Schemas["Schema Definitions"]
Assets["Material Assets"]
end
subgraph Implementations["Provider Implementations"]
Local["Local File System"]
Cloud["Cloud Service"]
Custom["Custom Provider"]
end
subgraph Repositories["Data Access Layer"]
JsonRepo["JSON Repository"]
VueRepo["Vue Repository"]
PluginRepo["Plugin Repository"]
StaticRepo["Static Repository"]
end
Designer -->|API Calls| Service
Runtime -->|API Calls| Service
Service -->|Abstract Methods| Local
Service -->|Extends| Cloud
Service -->|Extends| Custom
Local --> JsonRepo
Local --> VueRepo
Local --> PluginRepo
Local --> StaticRepo
Service -->|Uses Types| Schemas
Service -->|Uses Types| Assets
Service 抽象类定义了 Provider 实现的完整契约,位于 packages/core/src/protocols/service.ts。所有方法均返回 Promises 以支持跨不同存储后端的异步操作。
| 方法 | 目的 | 参数 | 返回类型 |
|---|---|---|---|
getExtension() | 获取设计器扩展配置 | - | Promise<VTJConfig | undefined> |
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 标志支持新项目创建和现有项目加载。
| 方法 | 目的 | 参数 | 返回类型 |
|---|---|---|---|
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 | Promise<boolean> |
文件操作使用 BlockSchema,它定义了完整的 DSL 结构,包括组件树 (nodes)、状态管理 (state, computed, watch)、生命周期钩子 (lifeCycles)、方法、样式和数据源。文件通过 PageFile 和 BlockFile 接口分类为 PageFile 或 BlockFile。
| 方法 | 目的 | 参数 | 返回类型 |
|---|---|---|---|
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 结构中)、标签和可选备注。
| 方法 | 目的 | 参数 | 返回类型 |
|---|---|---|---|
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 解析 中描述的双向转换。
| 方法 | 目的 | 参数 | 返回类型 |
|---|---|---|---|
uploadStaticFile() | 上传资源到项目 | file: File, projectId: string | Promise<StaticFileInfo | null> |
getStaticFiles() | 列出项目静态文件 | projectId: string | Promise<StaticFileInfo[]> |
removeStaticFile() | 删除静态资源 | name: string, projectId: string, file?: StaticFileInfo | Promise<boolean> |
clearStaticFiles() | 删除所有静态文件 | projectId: string | Promise<boolean> |
静态文件使用 StaticFileInfo 进行跟踪,其中包含可选的 ID、文件名和必需的文件路径属性。这些方法支持图片、样式表和其他资源的项目级资源管理。
| 方法 | 目的 | 参数 | 返回类型 |
|---|---|---|---|
getPluginMaterial() | 获取插件组件描述 | from: NodeFromPlugin | Promise<MaterialDescription | null> |
此方法支持从插件源动态加载物料,支持 NodeFromPlugin 接口,该接口定义了包含 URL 数组和可选库导出名称的插件类型。
ProjectSchema 接口代表完整的项目配置:
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,用于包含区域设置和消息定义的国际化BlockSchema 代表核心 DSL 结构:
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 映射NodeSchema 定义 DSL 树中的单个组件节点:
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:插槽放置定位,带有可选的作用域参数DataSourceSchema 支持声明式数据获取:
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 提供开发时的测试功能。
物料描述通过 MaterialDescription 接口定义可用组件:
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 通过专用接口区分静态值和运行时可执行代码:
interface JSExpression {
type: "JSExpression";
id?: string;
value: string;
}
interface JSFunction {
type: "JSFunction";
id?: string;
value: string;
}
这些接口使 DSL 结构能够区分字面量值和需要运行时求值的代码,支持 DSL Schema 和数据模型 中描述的声明式数据绑定模式。
VTJConfig 接口配置运行时行为:
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 扩展模式。
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,请扩展 Service 抽象类:
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:
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 方法应实现健壮的错误处理:
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 进行:
init() 检索完整项目 SchemasaveFile(),带有防抖功能saveHistoryItem() 捕获快照版本genVueContent() 为预览面板生成实时 Vue 代码getPluginMaterial() 获取动态组件描述渲染器通过以下方式使用 Provider API:
getExtension() 提供运行时 VTJConfig 设置Provider API 广泛利用 TypeScript 的类型系统:
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/ 中所实现。
Provider API 与其他核心系统协同工作:
要全面了解 VTJ 的架构模式,请查看 架构概览,它解释了 Provider 抽象层如何实现系统的可扩展性和平台可移植性。