@djvlc/runtime-host-vue 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +489 -0
- package/dist/index.d.cts +287 -0
- package/dist/index.d.ts +287 -0
- package/dist/index.js +458 -0
- package/package.json +55 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
// src/vue-runtime.ts
|
|
2
|
+
import { ref, shallowRef, readonly } from "vue";
|
|
3
|
+
import {
|
|
4
|
+
createRuntime
|
|
5
|
+
} from "@djvlc/runtime-core";
|
|
6
|
+
function createVueRuntime(options) {
|
|
7
|
+
const runtime = shallowRef(null);
|
|
8
|
+
const loading = ref(true);
|
|
9
|
+
const phase = ref("idle");
|
|
10
|
+
const page = shallowRef(null);
|
|
11
|
+
const error = shallowRef(null);
|
|
12
|
+
const hostApi = shallowRef(null);
|
|
13
|
+
const init = async () => {
|
|
14
|
+
const container = options.containerRef?.value;
|
|
15
|
+
if (!container) {
|
|
16
|
+
throw new Error("Container element not found");
|
|
17
|
+
}
|
|
18
|
+
const runtimeInstance = createRuntime({
|
|
19
|
+
...options,
|
|
20
|
+
container,
|
|
21
|
+
onError: (err) => {
|
|
22
|
+
error.value = err;
|
|
23
|
+
options.onError?.(err);
|
|
24
|
+
},
|
|
25
|
+
onEvent: (event) => {
|
|
26
|
+
options.onEvent?.(event);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
runtime.value = runtimeInstance;
|
|
30
|
+
runtimeInstance.onStateChange((state) => {
|
|
31
|
+
phase.value = state.phase;
|
|
32
|
+
loading.value = state.phase !== "ready" && state.phase !== "error";
|
|
33
|
+
if (state.page) {
|
|
34
|
+
page.value = state.page;
|
|
35
|
+
}
|
|
36
|
+
if (state.error) {
|
|
37
|
+
error.value = state.error;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
await runtimeInstance.init();
|
|
41
|
+
hostApi.value = runtimeInstance.getHostApi();
|
|
42
|
+
};
|
|
43
|
+
const load = async () => {
|
|
44
|
+
if (!runtime.value) {
|
|
45
|
+
throw new Error("Runtime not initialized");
|
|
46
|
+
}
|
|
47
|
+
const result = await runtime.value.load();
|
|
48
|
+
page.value = result;
|
|
49
|
+
hostApi.value = runtime.value.getHostApi();
|
|
50
|
+
return result;
|
|
51
|
+
};
|
|
52
|
+
const render = async () => {
|
|
53
|
+
if (!runtime.value) {
|
|
54
|
+
throw new Error("Runtime not initialized");
|
|
55
|
+
}
|
|
56
|
+
await runtime.value.render();
|
|
57
|
+
loading.value = false;
|
|
58
|
+
};
|
|
59
|
+
const destroy = () => {
|
|
60
|
+
runtime.value?.destroy();
|
|
61
|
+
runtime.value = null;
|
|
62
|
+
hostApi.value = null;
|
|
63
|
+
page.value = null;
|
|
64
|
+
error.value = null;
|
|
65
|
+
phase.value = "idle";
|
|
66
|
+
loading.value = true;
|
|
67
|
+
};
|
|
68
|
+
const setVariable = (key, value) => {
|
|
69
|
+
runtime.value?.setVariable(key, value);
|
|
70
|
+
};
|
|
71
|
+
const refreshData = async (queryId) => {
|
|
72
|
+
await runtime.value?.refreshData(queryId);
|
|
73
|
+
};
|
|
74
|
+
return {
|
|
75
|
+
runtime,
|
|
76
|
+
loading: readonly(loading),
|
|
77
|
+
phase: readonly(phase),
|
|
78
|
+
page,
|
|
79
|
+
error,
|
|
80
|
+
hostApi,
|
|
81
|
+
init,
|
|
82
|
+
load,
|
|
83
|
+
render,
|
|
84
|
+
destroy,
|
|
85
|
+
setVariable,
|
|
86
|
+
refreshData
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// src/components/DJVRenderer.ts
|
|
91
|
+
import {
|
|
92
|
+
defineComponent,
|
|
93
|
+
ref as ref3,
|
|
94
|
+
shallowRef as shallowRef2,
|
|
95
|
+
onMounted,
|
|
96
|
+
onUnmounted as onUnmounted2,
|
|
97
|
+
watch,
|
|
98
|
+
h
|
|
99
|
+
} from "vue";
|
|
100
|
+
|
|
101
|
+
// src/composables/useRuntime.ts
|
|
102
|
+
import { inject, provide, ref as ref2, computed, onUnmounted } from "vue";
|
|
103
|
+
var RuntimeContextKey = /* @__PURE__ */ Symbol("DJVRuntime");
|
|
104
|
+
function provideRuntime(value) {
|
|
105
|
+
provide(RuntimeContextKey, value);
|
|
106
|
+
}
|
|
107
|
+
function injectRuntime() {
|
|
108
|
+
const context = inject(RuntimeContextKey);
|
|
109
|
+
if (!context) {
|
|
110
|
+
throw new Error("useDJVRuntime must be used within a DJVProvider");
|
|
111
|
+
}
|
|
112
|
+
return context;
|
|
113
|
+
}
|
|
114
|
+
function useDJVRuntime() {
|
|
115
|
+
const context = injectRuntime();
|
|
116
|
+
return {
|
|
117
|
+
runtime: computed(() => context.value.runtime),
|
|
118
|
+
state: computed(() => context.value.state),
|
|
119
|
+
loading: computed(() => {
|
|
120
|
+
const phase = context.value.state.phase;
|
|
121
|
+
return phase !== "ready" && phase !== "error";
|
|
122
|
+
}),
|
|
123
|
+
phase: computed(() => context.value.state.phase),
|
|
124
|
+
error: computed(() => context.value.state.error),
|
|
125
|
+
page: computed(() => context.value.state.page)
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function useHostApi() {
|
|
129
|
+
const context = injectRuntime();
|
|
130
|
+
const hostApi = context.value.hostApi;
|
|
131
|
+
if (!hostApi) {
|
|
132
|
+
throw new Error("HostAPI not available. Make sure runtime is initialized.");
|
|
133
|
+
}
|
|
134
|
+
return hostApi;
|
|
135
|
+
}
|
|
136
|
+
function useRuntimeState(key) {
|
|
137
|
+
const context = injectRuntime();
|
|
138
|
+
return computed(() => {
|
|
139
|
+
return context.value.state.variables[key];
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
function useRuntimeStateWritable(key, defaultValue) {
|
|
143
|
+
const context = injectRuntime();
|
|
144
|
+
const value = computed(() => {
|
|
145
|
+
return context.value.state.variables[key] ?? defaultValue;
|
|
146
|
+
});
|
|
147
|
+
const setValue = (newValue) => {
|
|
148
|
+
context.value.runtime?.setVariable(key, newValue);
|
|
149
|
+
};
|
|
150
|
+
return [value, setValue];
|
|
151
|
+
}
|
|
152
|
+
function useQuery(queryId) {
|
|
153
|
+
const context = injectRuntime();
|
|
154
|
+
const loading = ref2(false);
|
|
155
|
+
const error = ref2(null);
|
|
156
|
+
const data = computed(() => {
|
|
157
|
+
return context.value.state.queries[queryId];
|
|
158
|
+
});
|
|
159
|
+
const refetch = async () => {
|
|
160
|
+
loading.value = true;
|
|
161
|
+
error.value = null;
|
|
162
|
+
try {
|
|
163
|
+
await context.value.runtime?.refreshData(queryId);
|
|
164
|
+
} catch (e) {
|
|
165
|
+
error.value = e;
|
|
166
|
+
} finally {
|
|
167
|
+
loading.value = false;
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
return {
|
|
171
|
+
data,
|
|
172
|
+
loading,
|
|
173
|
+
error,
|
|
174
|
+
refetch
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
function useAction(actionType) {
|
|
178
|
+
const context = injectRuntime();
|
|
179
|
+
const loading = ref2(false);
|
|
180
|
+
const result = ref2();
|
|
181
|
+
const error = ref2(null);
|
|
182
|
+
const execute = async (params) => {
|
|
183
|
+
const hostApi = context.value.hostApi;
|
|
184
|
+
if (!hostApi) {
|
|
185
|
+
throw new Error("HostAPI not available");
|
|
186
|
+
}
|
|
187
|
+
loading.value = true;
|
|
188
|
+
error.value = null;
|
|
189
|
+
try {
|
|
190
|
+
const response = await hostApi.executeAction(actionType, params);
|
|
191
|
+
if (response.success) {
|
|
192
|
+
result.value = response.data;
|
|
193
|
+
return response.data;
|
|
194
|
+
} else {
|
|
195
|
+
throw new Error(response.message || "Action failed");
|
|
196
|
+
}
|
|
197
|
+
} catch (e) {
|
|
198
|
+
error.value = e;
|
|
199
|
+
throw e;
|
|
200
|
+
} finally {
|
|
201
|
+
loading.value = false;
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
return {
|
|
205
|
+
execute,
|
|
206
|
+
loading,
|
|
207
|
+
result,
|
|
208
|
+
error
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
function useData(queryId, params, options) {
|
|
212
|
+
const context = injectRuntime();
|
|
213
|
+
const data = ref2();
|
|
214
|
+
const loading = ref2(false);
|
|
215
|
+
const error = ref2(null);
|
|
216
|
+
const refetch = async (newParams) => {
|
|
217
|
+
const hostApi = context.value.hostApi;
|
|
218
|
+
if (!hostApi) {
|
|
219
|
+
throw new Error("HostAPI not available");
|
|
220
|
+
}
|
|
221
|
+
loading.value = true;
|
|
222
|
+
error.value = null;
|
|
223
|
+
try {
|
|
224
|
+
const response = await hostApi.requestData(
|
|
225
|
+
queryId,
|
|
226
|
+
newParams || params
|
|
227
|
+
);
|
|
228
|
+
if (response.success) {
|
|
229
|
+
data.value = response.data;
|
|
230
|
+
} else {
|
|
231
|
+
throw new Error(response.message || "Query failed");
|
|
232
|
+
}
|
|
233
|
+
} catch (e) {
|
|
234
|
+
error.value = e;
|
|
235
|
+
} finally {
|
|
236
|
+
loading.value = false;
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
if (options?.immediate !== false) {
|
|
240
|
+
refetch();
|
|
241
|
+
}
|
|
242
|
+
return {
|
|
243
|
+
data,
|
|
244
|
+
loading,
|
|
245
|
+
error,
|
|
246
|
+
refetch
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
function useRuntimeEvent(eventType, handler) {
|
|
250
|
+
const context = injectRuntime();
|
|
251
|
+
const unsubscribe = context.value.runtime?.on(eventType, (event) => {
|
|
252
|
+
handler(event.data);
|
|
253
|
+
});
|
|
254
|
+
onUnmounted(() => {
|
|
255
|
+
unsubscribe?.();
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// src/components/DJVRenderer.ts
|
|
260
|
+
var DJVRenderer = defineComponent({
|
|
261
|
+
name: "DJVRenderer",
|
|
262
|
+
props: {
|
|
263
|
+
pageUid: {
|
|
264
|
+
type: String,
|
|
265
|
+
required: true
|
|
266
|
+
},
|
|
267
|
+
apiBaseUrl: {
|
|
268
|
+
type: String,
|
|
269
|
+
required: true
|
|
270
|
+
},
|
|
271
|
+
cdnBaseUrl: {
|
|
272
|
+
type: String,
|
|
273
|
+
required: true
|
|
274
|
+
},
|
|
275
|
+
channel: {
|
|
276
|
+
type: String,
|
|
277
|
+
default: "prod"
|
|
278
|
+
},
|
|
279
|
+
userId: String,
|
|
280
|
+
deviceId: String,
|
|
281
|
+
authToken: String,
|
|
282
|
+
previewToken: String,
|
|
283
|
+
debug: {
|
|
284
|
+
type: Boolean,
|
|
285
|
+
default: false
|
|
286
|
+
},
|
|
287
|
+
enableSRI: {
|
|
288
|
+
type: Boolean,
|
|
289
|
+
default: true
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
emits: ["load", "error", "ready"],
|
|
293
|
+
setup(props, { emit, slots }) {
|
|
294
|
+
const containerRef = ref3(null);
|
|
295
|
+
const contextValue = shallowRef2({
|
|
296
|
+
runtime: null,
|
|
297
|
+
state: {
|
|
298
|
+
phase: "idle",
|
|
299
|
+
page: null,
|
|
300
|
+
variables: {},
|
|
301
|
+
queries: {},
|
|
302
|
+
components: /* @__PURE__ */ new Map(),
|
|
303
|
+
error: null,
|
|
304
|
+
destroyed: false
|
|
305
|
+
},
|
|
306
|
+
hostApi: null
|
|
307
|
+
});
|
|
308
|
+
provideRuntime(contextValue);
|
|
309
|
+
let vueRuntime = null;
|
|
310
|
+
const initAndLoad = async () => {
|
|
311
|
+
if (!containerRef.value) return;
|
|
312
|
+
const options = {
|
|
313
|
+
pageUid: props.pageUid,
|
|
314
|
+
apiBaseUrl: props.apiBaseUrl,
|
|
315
|
+
cdnBaseUrl: props.cdnBaseUrl,
|
|
316
|
+
channel: props.channel,
|
|
317
|
+
userId: props.userId,
|
|
318
|
+
deviceId: props.deviceId,
|
|
319
|
+
authToken: props.authToken,
|
|
320
|
+
previewToken: props.previewToken,
|
|
321
|
+
debug: props.debug,
|
|
322
|
+
enableSRI: props.enableSRI,
|
|
323
|
+
containerRef,
|
|
324
|
+
onError: (error) => {
|
|
325
|
+
emit("error", error);
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
vueRuntime = createVueRuntime(options);
|
|
329
|
+
try {
|
|
330
|
+
await vueRuntime.init();
|
|
331
|
+
contextValue.value = {
|
|
332
|
+
runtime: vueRuntime.runtime.value,
|
|
333
|
+
state: vueRuntime.runtime.value?.getState() || contextValue.value.state,
|
|
334
|
+
hostApi: vueRuntime.hostApi.value
|
|
335
|
+
};
|
|
336
|
+
const page = await vueRuntime.load();
|
|
337
|
+
emit("load", page);
|
|
338
|
+
contextValue.value = {
|
|
339
|
+
...contextValue.value,
|
|
340
|
+
state: vueRuntime.runtime.value?.getState() || contextValue.value.state,
|
|
341
|
+
hostApi: vueRuntime.hostApi.value
|
|
342
|
+
};
|
|
343
|
+
await vueRuntime.render();
|
|
344
|
+
emit("ready");
|
|
345
|
+
vueRuntime.runtime.value?.onStateChange((state) => {
|
|
346
|
+
contextValue.value = {
|
|
347
|
+
...contextValue.value,
|
|
348
|
+
state
|
|
349
|
+
};
|
|
350
|
+
});
|
|
351
|
+
} catch (error) {
|
|
352
|
+
emit("error", error);
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
onMounted(() => {
|
|
356
|
+
initAndLoad();
|
|
357
|
+
});
|
|
358
|
+
onUnmounted2(() => {
|
|
359
|
+
vueRuntime?.destroy();
|
|
360
|
+
});
|
|
361
|
+
watch(
|
|
362
|
+
() => props.pageUid,
|
|
363
|
+
() => {
|
|
364
|
+
vueRuntime?.destroy();
|
|
365
|
+
initAndLoad();
|
|
366
|
+
}
|
|
367
|
+
);
|
|
368
|
+
return () => {
|
|
369
|
+
return h(
|
|
370
|
+
"div",
|
|
371
|
+
{
|
|
372
|
+
ref: containerRef,
|
|
373
|
+
class: "djvlc-renderer"
|
|
374
|
+
},
|
|
375
|
+
[
|
|
376
|
+
// 加载中插槽
|
|
377
|
+
vueRuntime?.loading.value && slots.loading?.(),
|
|
378
|
+
// 错误插槽
|
|
379
|
+
vueRuntime?.error.value && slots.error?.({ error: vueRuntime.error.value }),
|
|
380
|
+
// 默认插槽(额外内容)
|
|
381
|
+
slots.default?.()
|
|
382
|
+
]
|
|
383
|
+
);
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
// src/components/DJVProvider.ts
|
|
389
|
+
import { defineComponent as defineComponent2, shallowRef as shallowRef3, h as h2 } from "vue";
|
|
390
|
+
var DJVProvider = defineComponent2({
|
|
391
|
+
name: "DJVProvider",
|
|
392
|
+
props: {
|
|
393
|
+
runtime: {
|
|
394
|
+
type: Object,
|
|
395
|
+
default: null
|
|
396
|
+
},
|
|
397
|
+
hostApi: {
|
|
398
|
+
type: Object,
|
|
399
|
+
default: null
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
setup(props, { slots }) {
|
|
403
|
+
const contextValue = shallowRef3({
|
|
404
|
+
runtime: props.runtime,
|
|
405
|
+
state: props.runtime?.getState() || {
|
|
406
|
+
phase: "idle",
|
|
407
|
+
page: null,
|
|
408
|
+
variables: {},
|
|
409
|
+
queries: {},
|
|
410
|
+
components: /* @__PURE__ */ new Map(),
|
|
411
|
+
error: null,
|
|
412
|
+
destroyed: false
|
|
413
|
+
},
|
|
414
|
+
hostApi: props.hostApi
|
|
415
|
+
});
|
|
416
|
+
provideRuntime(contextValue);
|
|
417
|
+
if (props.runtime) {
|
|
418
|
+
props.runtime.onStateChange((state) => {
|
|
419
|
+
contextValue.value = {
|
|
420
|
+
...contextValue.value,
|
|
421
|
+
state
|
|
422
|
+
};
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
return () => h2("div", { class: "djvlc-provider" }, slots.default?.());
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
// src/plugin.ts
|
|
430
|
+
var DJVPlugin = {
|
|
431
|
+
install(app, options = {}) {
|
|
432
|
+
if (options.registerComponents !== false) {
|
|
433
|
+
app.component("DJVRenderer", DJVRenderer);
|
|
434
|
+
app.component("DJVProvider", DJVProvider);
|
|
435
|
+
}
|
|
436
|
+
app.provide("djvlc-config", {
|
|
437
|
+
apiBaseUrl: options.defaultApiBaseUrl,
|
|
438
|
+
cdnBaseUrl: options.defaultCdnBaseUrl
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
export {
|
|
443
|
+
DJVPlugin,
|
|
444
|
+
DJVProvider,
|
|
445
|
+
DJVRenderer,
|
|
446
|
+
RuntimeContextKey,
|
|
447
|
+
createVueRuntime,
|
|
448
|
+
injectRuntime,
|
|
449
|
+
provideRuntime,
|
|
450
|
+
useAction,
|
|
451
|
+
useDJVRuntime,
|
|
452
|
+
useData,
|
|
453
|
+
useHostApi,
|
|
454
|
+
useQuery,
|
|
455
|
+
useRuntimeEvent,
|
|
456
|
+
useRuntimeState,
|
|
457
|
+
useRuntimeStateWritable
|
|
458
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@djvlc/runtime-host-vue",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "DJV 低代码平台 Vue3 宿主适配器",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsup src/index.ts --format esm,cjs --dts --clean --external vue",
|
|
21
|
+
"dev": "tsup src/index.ts --format esm,cjs --dts --watch --external vue",
|
|
22
|
+
"test": "vitest run --passWithNoTests",
|
|
23
|
+
"test:watch": "vitest",
|
|
24
|
+
"lint": "eslint src --ext .ts,.vue",
|
|
25
|
+
"typecheck": "vue-tsc --noEmit",
|
|
26
|
+
"clean": "rimraf dist"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@djvlc/runtime-core": "1.0.0",
|
|
30
|
+
"@djvlc/contracts-types": "^1.4.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^20.10.0",
|
|
34
|
+
"eslint": "^8.55.0",
|
|
35
|
+
"rimraf": "^5.0.5",
|
|
36
|
+
"tsup": "^8.0.0",
|
|
37
|
+
"typescript": "^5.3.0",
|
|
38
|
+
"vitest": "^1.0.0",
|
|
39
|
+
"vue-tsc": "^2.0.0"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"vue": "^3.3.0"
|
|
43
|
+
},
|
|
44
|
+
"keywords": [
|
|
45
|
+
"lowcode",
|
|
46
|
+
"runtime",
|
|
47
|
+
"vue",
|
|
48
|
+
"vue3",
|
|
49
|
+
"djv"
|
|
50
|
+
],
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"access": "public"
|
|
53
|
+
},
|
|
54
|
+
"license": "MIT"
|
|
55
|
+
}
|