@web-widget/vue 3.0.0-beta.3 → 3.0.0-beta.5

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.
@@ -0,0 +1,174 @@
1
+ // src/error-handler.ts
2
+ import { cacheProviderIsLoading } from "@web-widget/helpers/cache";
3
+ function installErrorHandler(app, callback, throwUnhandledErrorInProduction = false) {
4
+ app.config.throwUnhandledErrorInProduction = throwUnhandledErrorInProduction;
5
+ app.config.errorHandler = (err, instance, info) => {
6
+ if (cacheProviderIsLoading(err)) {
7
+ return;
8
+ }
9
+ app.config.warnHandler = () => {
10
+ };
11
+ callback(err);
12
+ };
13
+ }
14
+
15
+ // src/components.ts
16
+ import { WebWidgetRenderer } from "@web-widget/web-widget";
17
+ import {
18
+ h,
19
+ cloneVNode,
20
+ defineComponent,
21
+ Suspense,
22
+ useAttrs,
23
+ getCurrentInstance,
24
+ ref,
25
+ onErrorCaptured
26
+ } from "vue";
27
+ function renderLightChildren(slots) {
28
+ return Object.entries(slots).flatMap(
29
+ ([name, render]) => render ? render().map(
30
+ (node) => name === "default" ? node : cloneVNode(node, { slot: name })
31
+ ) : []
32
+ );
33
+ }
34
+ var ServerWebWidget = /* @__PURE__ */ defineComponent({
35
+ name: "ServerWebWidget",
36
+ props: {
37
+ errorFallback: {
38
+ type: Object,
39
+ default: null
40
+ },
41
+ renderer: {
42
+ type: Object,
43
+ required: true
44
+ },
45
+ renderChildren: {
46
+ type: Function,
47
+ required: true
48
+ }
49
+ },
50
+ async setup({ renderer, errorFallback, renderChildren }, { slots }) {
51
+ const parent = getCurrentInstance();
52
+ const children = Object.keys(slots).length ? await renderChildren(renderLightChildren(slots), parent) : "";
53
+ const tag = renderer.localName;
54
+ const attrs = renderer.attributes;
55
+ const innerHTML = await renderer.renderInnerHTMLToString({ children }).catch((err) => {
56
+ const error = err instanceof Error ? err : new Error(String(err));
57
+ console.error("[VueWidget] Rendering error:", error);
58
+ return error;
59
+ });
60
+ if (innerHTML instanceof Error) {
61
+ return () => errorFallback;
62
+ }
63
+ return () => h(tag, { ...attrs, innerHTML });
64
+ }
65
+ });
66
+ function resolveFallback(fallback) {
67
+ var _a;
68
+ if (fallback !== null && typeof fallback === "object" && !("__v_isVNode" in fallback) && ("pending" in fallback || "error" in fallback)) {
69
+ const obj = fallback;
70
+ return {
71
+ pendingFallback: obj.pending,
72
+ errorFallback: (_a = obj.error) != null ? _a : obj.pending
73
+ };
74
+ }
75
+ return {
76
+ pendingFallback: fallback,
77
+ errorFallback: fallback
78
+ };
79
+ }
80
+ function createWidgetAdapter(renderChildren) {
81
+ return (loader, options = {}) => defineComponent({
82
+ name: "VueWidget",
83
+ inheritAttrs: false,
84
+ props: {
85
+ widget: {
86
+ type: Object,
87
+ default: () => ({})
88
+ }
89
+ },
90
+ setup({ widget }, { slots }) {
91
+ const { fallback, id, loading = options.loading, clientOnly } = widget;
92
+ const { pendingFallback, errorFallback } = resolveFallback(fallback);
93
+ const renderOptions = {
94
+ ...options,
95
+ clientOnly: widget.clientOnly,
96
+ id,
97
+ loading: loading != null ? loading : options.loading,
98
+ serverOnly: widget.serverOnly
99
+ };
100
+ const attrs = { ...useAttrs() };
101
+ const slot = typeof attrs.slot === "string" ? attrs.slot : void 0;
102
+ delete attrs.slot;
103
+ const data = attrs;
104
+ const renderer = new WebWidgetRenderer(loader, {
105
+ ...renderOptions,
106
+ data,
107
+ slot
108
+ });
109
+ if (renderer.opaqueInnerHTML !== void 0) {
110
+ return () => {
111
+ const lightChildren = Object.keys(slots).length ? renderLightChildren(slots) : [];
112
+ return h(
113
+ renderer.localName,
114
+ {
115
+ ...renderer.attributes,
116
+ ...lightChildren.length === 0 ? { innerHTML: renderer.opaqueInnerHTML } : null
117
+ },
118
+ lightChildren.length ? lightChildren : void 0
119
+ );
120
+ };
121
+ }
122
+ if (clientOnly && pendingFallback) {
123
+ return () => h(
124
+ renderer.localName,
125
+ renderer.attributes,
126
+ h(
127
+ renderer.pendingBoundary.localName,
128
+ {
129
+ "aria-busy": renderer.pendingBoundary.ariaBusy,
130
+ slot: renderer.pendingBoundary.slot,
131
+ style: { display: renderer.pendingBoundary.display }
132
+ },
133
+ pendingFallback
134
+ )
135
+ );
136
+ }
137
+ if (!renderChildren) {
138
+ throw new TypeError("Missing server children renderer.");
139
+ }
140
+ const error = ref(null);
141
+ onErrorCaptured((err) => {
142
+ error.value = err;
143
+ return false;
144
+ });
145
+ return () => {
146
+ if (error.value && errorFallback) {
147
+ return errorFallback;
148
+ }
149
+ return h(
150
+ Suspense,
151
+ {},
152
+ {
153
+ default: h(
154
+ ServerWebWidget,
155
+ {
156
+ errorFallback,
157
+ renderChildren,
158
+ renderer
159
+ },
160
+ slots
161
+ ),
162
+ fallback: pendingFallback
163
+ }
164
+ );
165
+ };
166
+ }
167
+ });
168
+ }
169
+
170
+ export {
171
+ installErrorHandler,
172
+ resolveFallback,
173
+ createWidgetAdapter
174
+ };
@@ -0,0 +1,48 @@
1
+ import { WidgetHostProps, WidgetContainerProps, WidgetContainerOptions, ExtractWidgetProps, WidgetModuleLoader } from '@web-widget/schema';
2
+ import { DefineComponent, VNode, App, Component } from 'vue';
3
+
4
+ /**
5
+ * A Vue component wrapping a widget, with props `T` plus container config.
6
+ */
7
+ type VueWidgetComponent<T = unknown> = DefineComponent<T & WidgetHostProps & {
8
+ widget?: VueWidgetContainerProps;
9
+ }>;
10
+ type VueWidgetContainerProps = WidgetContainerProps<VNode>;
11
+ /**
12
+ * Resolve a WidgetFallback into separate pending and error VNodes.
13
+ * - `VNode` — used for both pending and error.
14
+ * - `{ pending?, error? }` — specify independently; `error` defaults to `pending`.
15
+ */
16
+ declare function resolveFallback(fallback: VueWidgetContainerProps['fallback']): {
17
+ pendingFallback: VNode;
18
+ errorFallback: VNode;
19
+ };
20
+ /**
21
+ * Container function (AdapterModule contract).
22
+ *
23
+ * Wraps a widget module loader into a Vue component with props type
24
+ * inference from the source module's default export.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * import { widget } from '@web-widget/vue/adapter';
29
+ *
30
+ * const Counter = widget(() => import('./Counter@widget.vue'));
31
+ * // ^? VueWidgetComponent<{ count: number }>
32
+ * ```
33
+ */
34
+ interface VueWidgetFactory {
35
+ <M>(loader: () => Promise<M>, options?: WidgetContainerOptions): VueWidgetComponent<ExtractWidgetProps<M>>;
36
+ <Props>(loader: WidgetModuleLoader, options?: WidgetContainerOptions): VueWidgetComponent<Props>;
37
+ }
38
+
39
+ interface CreateVueRenderOptions {
40
+ onCreatedApp?: (app: App<Element>, context: {
41
+ container?: Element | DocumentFragment;
42
+ data: any;
43
+ progressive?: boolean;
44
+ recovering?: boolean;
45
+ }, component: Component, props: any) => Promise<void>;
46
+ }
47
+
48
+ export { type CreateVueRenderOptions as C, type VueWidgetFactory as V, type VueWidgetComponent as a, type VueWidgetContainerProps as b, resolveFallback as r };
@@ -1,14 +1,15 @@
1
1
  import * as _web_widget_schema from '@web-widget/schema';
2
+ export { WidgetContainerOptions } from '@web-widget/schema';
3
+ import { C as CreateVueRenderOptions, V as VueWidgetFactory } from './types-Q7wIvDbF.js';
4
+ export { a as VueWidgetComponent, b as VueWidgetContainerProps, r as resolveFallback } from './types-Q7wIvDbF.js';
2
5
  import { Component } from 'vue';
3
- import { C as CreateVueRenderOptions } from './types-eCw5P8fo.js';
4
- export { D as DefineWebWidgetOptions, V as VueWidgetComponent, W as WidgetContainerConfig, a as WidgetFallback, c as container, r as resolveFallback } from './types-eCw5P8fo.js';
5
6
  export { asReactWidget, toReact } from './vue.js';
6
- import '@web-widget/web-widget';
7
7
  import '@web-widget/react/adapter';
8
8
 
9
+ declare const widget: VueWidgetFactory;
9
10
  declare const createVueRender: ({ onCreatedApp, }?: CreateVueRenderOptions) => _web_widget_schema.ClientRender<Component, unknown, _web_widget_schema.ClientRenderOptions, void | _web_widget_schema.ClientRenderResult<unknown>>;
10
11
  /**@deprecated Please use `createVueRender` instead.*/
11
12
  declare const defineVueRender: ({ onCreatedApp, }?: CreateVueRenderOptions) => _web_widget_schema.ClientRender<Component, unknown, _web_widget_schema.ClientRenderOptions, void | _web_widget_schema.ClientRenderResult<unknown>>;
12
13
  declare const render: _web_widget_schema.ClientRender<Component, unknown, _web_widget_schema.ClientRenderOptions, void | _web_widget_schema.ClientRenderResult<unknown>>;
13
14
 
14
- export { createVueRender, defineVueRender, render };
15
+ export { VueWidgetFactory, createVueRender, defineVueRender, render, widget };
@@ -1,8 +1,8 @@
1
1
  import {
2
- container,
2
+ createWidgetAdapter,
3
3
  installErrorHandler,
4
4
  resolveFallback
5
- } from "./chunk-7BZH43RE.js";
5
+ } from "./chunk-ER6EL6Y7.js";
6
6
  import {
7
7
  asReactWidget,
8
8
  toReact
@@ -11,22 +11,23 @@ import {
11
11
  // src/adapter.client.ts
12
12
  import { defineClientRender } from "@web-widget/helpers";
13
13
  import { Suspense, createApp, createSSRApp, h } from "vue";
14
+ var widget = createWidgetAdapter();
14
15
  var createWidgetSuspense = (component) => (props) => h(Suspense, null, [h(component, props)]);
15
16
  var createVueRender = ({
16
17
  onCreatedApp = async () => {
17
18
  }
18
19
  } = {}) => {
19
20
  return defineClientRender(
20
- async (component, data, { recovering, container: container2 }) => {
21
+ async (component, data, { recovering, container }) => {
21
22
  data = data != null ? data : {};
22
23
  if (!component) {
23
24
  throw new TypeError(`Missing component.`);
24
25
  }
25
- if (!container2) {
26
+ if (!container) {
26
27
  throw new Error(`Missing container.`);
27
28
  }
28
29
  let app;
29
- const context = { data, recovering, container: container2 };
30
+ const context = { data, recovering, container };
30
31
  const WidgetSuspense = createWidgetSuspense(component);
31
32
  return {
32
33
  async mount() {
@@ -36,7 +37,7 @@ var createVueRender = ({
36
37
  error = err;
37
38
  });
38
39
  await onCreatedApp(app, context, component, data);
39
- app.mount(container2);
40
+ app.mount(container);
40
41
  if (error) {
41
42
  throw error;
42
43
  }
@@ -53,10 +54,10 @@ var defineVueRender = createVueRender;
53
54
  var render = createVueRender();
54
55
  export {
55
56
  asReactWidget,
56
- container,
57
57
  createVueRender,
58
58
  defineVueRender,
59
59
  render,
60
60
  resolveFallback,
61
- toReact
61
+ toReact,
62
+ widget
62
63
  };
@@ -1,10 +1,10 @@
1
1
  import * as _web_widget_schema from '@web-widget/schema';
2
+ export { WidgetContainerOptions } from '@web-widget/schema';
3
+ import { C as CreateVueRenderOptions, V as VueWidgetFactory } from './types-Q7wIvDbF.js';
4
+ export { a as VueWidgetComponent, b as VueWidgetContainerProps, r as resolveFallback } from './types-Q7wIvDbF.js';
2
5
  import { Component } from 'vue';
3
6
  import { SSRContext } from 'vue/server-renderer';
4
- import { C as CreateVueRenderOptions } from './types-eCw5P8fo.js';
5
- export { D as DefineWebWidgetOptions, V as VueWidgetComponent, W as WidgetContainerConfig, a as WidgetFallback, c as container, r as resolveFallback } from './types-eCw5P8fo.js';
6
7
  export { asReactWidget, toReact } from './vue.js';
7
- import '@web-widget/web-widget';
8
8
  import '@web-widget/react/adapter';
9
9
 
10
10
  declare module '@web-widget/schema' {
@@ -13,6 +13,7 @@ declare module '@web-widget/schema' {
13
13
  }
14
14
  }
15
15
 
16
+ declare const widget: VueWidgetFactory;
16
17
  interface VueRenderOptions {
17
18
  vue?: SSRContext;
18
19
  }
@@ -21,4 +22,4 @@ declare const createVueRender: ({ onCreatedApp, }?: CreateVueRenderOptions) => _
21
22
  declare const defineVueRender: ({ onCreatedApp, }?: CreateVueRenderOptions) => _web_widget_schema.ServerRender<Component, unknown, _web_widget_schema.ServerRenderOptions, _web_widget_schema.ServerRenderResult>;
22
23
  declare const render: _web_widget_schema.ServerRender<Component, unknown, _web_widget_schema.ServerRenderOptions, _web_widget_schema.ServerRenderResult>;
23
24
 
24
- export { type VueRenderOptions, createVueRender, defineVueRender, render };
25
+ export { type VueRenderOptions, VueWidgetFactory, createVueRender, defineVueRender, render, widget };
@@ -1,8 +1,8 @@
1
1
  import {
2
- container,
2
+ createWidgetAdapter,
3
3
  installErrorHandler,
4
4
  resolveFallback
5
- } from "./chunk-7BZH43RE.js";
5
+ } from "./chunk-ER6EL6Y7.js";
6
6
  import {
7
7
  asReactWidget,
8
8
  toReact
@@ -13,8 +13,25 @@ import { defineServerRender } from "@web-widget/helpers";
13
13
  import { createSSRApp, h, Suspense } from "vue";
14
14
  import {
15
15
  renderToString,
16
- renderToWebStream
16
+ renderToWebStream,
17
+ ssrRenderVNode
17
18
  } from "vue/server-renderer";
19
+ async function resolveSSRBuffer(value) {
20
+ const resolved = await value;
21
+ if (Array.isArray(resolved)) {
22
+ let html = "";
23
+ for (const item of resolved) html += await resolveSSRBuffer(item);
24
+ return html;
25
+ }
26
+ return typeof resolved === "string" ? resolved : "";
27
+ }
28
+ var widget = createWidgetAdapter(async (nodes, parent) => {
29
+ const buffer = [];
30
+ for (const node of nodes) {
31
+ ssrRenderVNode((item) => buffer.push(item), node, parent);
32
+ }
33
+ return resolveSSRBuffer(buffer);
34
+ });
18
35
  var createWidgetSuspense = (component) => (props) => h(Suspense, null, [h(component, props)]);
19
36
  var createVueRender = ({
20
37
  onCreatedApp = async () => {
@@ -37,8 +54,8 @@ var createVueRender = ({
37
54
  });
38
55
  await onCreatedApp(app, context, component, data);
39
56
  if (progressive) {
40
- const stream = renderToWebStream(app, ssrContext);
41
- const reader = stream.getReader();
57
+ const byteStream = renderToWebStream(app, ssrContext);
58
+ const reader = byteStream.getReader();
42
59
  const first = await reader.read();
43
60
  try {
44
61
  if (ssrContext == null ? void 0 : ssrContext.teleports) {
@@ -99,10 +116,10 @@ var defineVueRender = createVueRender;
99
116
  var render = createVueRender();
100
117
  export {
101
118
  asReactWidget,
102
- container,
103
119
  createVueRender,
104
120
  defineVueRender,
105
121
  render,
106
122
  resolveFallback,
107
- toReact
123
+ toReact,
124
+ widget
108
125
  };
package/dist/vue.d.ts CHANGED
@@ -4,15 +4,15 @@ import { ReactWidgetComponent } from '@web-widget/react/adapter';
4
4
  /**
5
5
  * Adapt Vue component types to React widget component types.
6
6
  *
7
- * @deprecated Use `container()` from `@web-widget/react/adapter` instead.
7
+ * @deprecated Use `widget()` from `@web-widget/react/adapter` instead.
8
8
  * The build tool automatically infers props types for both static imports
9
- * and explicit `container(() => import(...))` calls.
9
+ * and explicit `widget(() => import(...))` calls.
10
10
  *
11
11
  * This is a type-level cast only — the actual cross-framework rendering
12
12
  * is handled by the `@widget` system.
13
13
  */
14
14
  declare function asReactWidget<T>(component: Component<T>): ReactWidgetComponent<Omit<T, keyof ComponentPublicInstance | "$route" | "$router">>;
15
- /** @deprecated Use `container()` from `@web-widget/react/adapter` instead. */
15
+ /** @deprecated Use `widget()` from `@web-widget/react/adapter` instead. */
16
16
  declare const toReact: typeof asReactWidget;
17
17
 
18
18
  export { asReactWidget, toReact };
@@ -0,0 +1,11 @@
1
+ declare const _default: {
2
+ name: string;
3
+ extensions: string[];
4
+ adapter: string;
5
+ deriveExports: {
6
+ name: string;
7
+ default: string;
8
+ }[];
9
+ };
10
+
11
+ export { _default as default };
@@ -0,0 +1,13 @@
1
+ // src/transform.ts
2
+ var transform_default = {
3
+ name: "vue",
4
+ extensions: [".vue"],
5
+ adapter: "@web-widget/vue/adapter",
6
+ deriveExports: [
7
+ { name: "handler", default: "{GET({html}){return html()}}" },
8
+ { name: "meta", default: "{}" }
9
+ ]
10
+ };
11
+ export {
12
+ transform_default as default
13
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@web-widget/vue",
3
3
  "description": "Vue adapter",
4
- "version": "3.0.0-beta.3",
4
+ "version": "3.0.0-beta.5",
5
5
  "homepage": "https://github.com/web-widget/web-widget#readme",
6
6
  "repository": {
7
7
  "type": "git",
@@ -13,54 +13,47 @@
13
13
  },
14
14
  "license": "MIT",
15
15
  "dependencies": {
16
- "@web-widget/helpers": "3.0.0-beta.3",
17
- "@web-widget/web-widget": "3.0.0-beta.3",
18
- "@web-widget/schema": "3.0.0-beta.3",
19
- "@web-widget/react": "3.0.0-beta.3"
16
+ "@web-widget/helpers": "workspace:*",
17
+ "@web-widget/web-widget": "workspace:*",
18
+ "@web-widget/schema": "workspace:*",
19
+ "@web-widget/react": "workspace:*"
20
20
  },
21
21
  "devDependencies": {
22
- "tsup": "^8.3.4",
23
- "typescript": "^5.9.3",
22
+ "happy-dom": "14.12.3",
23
+ "tsup": "catalog:",
24
+ "typescript": "catalog:",
25
+ "vitest": "catalog:",
24
26
  "vue": "^3.5.34"
25
27
  },
26
28
  "exports": {
27
29
  ".": {
28
30
  "types": "./dist/vue.d.ts",
31
+ "development": "./src/index.ts",
29
32
  "default": "./dist/vue.js"
30
33
  },
34
+ "./transform": {
35
+ "types": "./dist/vue.transform.d.ts",
36
+ "development": "./src/transform.ts",
37
+ "default": "./dist/vue.transform.js"
38
+ },
31
39
  "./adapter": {
32
40
  "worker": {
33
41
  "types": "./dist/vue.adapter.server.d.ts",
42
+ "development": "./src/adapter.server.ts",
34
43
  "default": "./dist/vue.adapter.server.js"
35
44
  },
36
45
  "browser": {
37
46
  "types": "./dist/vue.adapter.client.d.ts",
47
+ "development": "./src/adapter.client.ts",
38
48
  "default": "./dist/vue.adapter.client.js"
39
49
  },
40
50
  "default": {
41
51
  "types": "./dist/vue.adapter.server.d.ts",
52
+ "development": "./src/adapter.server.ts",
42
53
  "default": "./dist/vue.adapter.server.js"
43
54
  }
44
55
  }
45
56
  },
46
- "webWidgetAdapter": {
47
- "version": "1.0.0",
48
- "name": "vue",
49
- "extensions": [
50
- ".vue"
51
- ],
52
- "adapter": "./adapter",
53
- "deriveExports": [
54
- {
55
- "name": "handler",
56
- "default": "{GET({html}){return html()}}"
57
- },
58
- {
59
- "name": "meta",
60
- "default": "{}"
61
- }
62
- ]
63
- },
64
57
  "files": [
65
58
  "dist"
66
59
  ],
@@ -68,16 +61,41 @@
68
61
  "vue": ">3.3.3"
69
62
  },
70
63
  "publishConfig": {
71
- "access": "public"
64
+ "access": "public",
65
+ "exports": {
66
+ ".": {
67
+ "types": "./dist/vue.d.ts",
68
+ "default": "./dist/vue.js"
69
+ },
70
+ "./transform": {
71
+ "types": "./dist/vue.transform.d.ts",
72
+ "default": "./dist/vue.transform.js"
73
+ },
74
+ "./adapter": {
75
+ "worker": {
76
+ "types": "./dist/vue.adapter.server.d.ts",
77
+ "default": "./dist/vue.adapter.server.js"
78
+ },
79
+ "browser": {
80
+ "types": "./dist/vue.adapter.client.d.ts",
81
+ "default": "./dist/vue.adapter.client.js"
82
+ },
83
+ "default": {
84
+ "types": "./dist/vue.adapter.server.d.ts",
85
+ "default": "./dist/vue.adapter.server.js"
86
+ }
87
+ }
88
+ }
72
89
  },
73
- "sideEffects": false,
74
- "type": "module",
75
90
  "scripts": {
76
91
  "build": "pnpm exec tsup",
77
92
  "clean:build": "rm -rf dist",
78
93
  "clean:node": "rm -rf node_modules",
79
94
  "dev": "pnpm exec tsup --watch",
80
95
  "lint": "eslint src",
81
- "prebuild": "pnpm run clean:build"
82
- }
83
- }
96
+ "prebuild": "pnpm run clean:build",
97
+ "test": "vitest run"
98
+ },
99
+ "sideEffects": false,
100
+ "type": "module"
101
+ }
@@ -1,200 +0,0 @@
1
- // src/error-handler.ts
2
- import { cacheProviderIsLoading } from "@web-widget/helpers/cache";
3
- function installErrorHandler(app, callback, throwUnhandledErrorInProduction = false) {
4
- app.config.throwUnhandledErrorInProduction = throwUnhandledErrorInProduction;
5
- app.config.errorHandler = (err, instance, info) => {
6
- if (cacheProviderIsLoading(err)) {
7
- return;
8
- }
9
- app.config.warnHandler = () => {
10
- };
11
- callback(err);
12
- };
13
- }
14
-
15
- // src/components.ts
16
- import { WebWidgetRenderer } from "@web-widget/web-widget";
17
- import {
18
- h,
19
- defineComponent,
20
- Suspense,
21
- useAttrs,
22
- ref,
23
- onErrorCaptured
24
- } from "vue";
25
- import { IS_CLIENT } from "@web-widget/helpers/env";
26
- var WebWidget = /* @__PURE__ */ defineComponent({
27
- name: "WebWidgetRoot",
28
- props: {
29
- base: {
30
- type: String
31
- },
32
- data: {
33
- type: Object,
34
- default: () => ({})
35
- },
36
- errorFallback: {
37
- type: Object,
38
- default: null
39
- },
40
- import: {
41
- type: String
42
- },
43
- inactive: {
44
- type: Boolean,
45
- default: false
46
- },
47
- loader: {
48
- type: Function,
49
- required: true
50
- },
51
- loading: {
52
- type: String
53
- },
54
- meta: {
55
- type: Object
56
- },
57
- name: {
58
- type: String
59
- },
60
- renderStage: {
61
- type: String
62
- },
63
- renderTarget: {
64
- type: String,
65
- default: "light"
66
- }
67
- },
68
- async setup({ loader, errorFallback, ...props }, { slots }) {
69
- if (!loader) {
70
- throw new TypeError(`Missing loader.`);
71
- }
72
- if (Object.keys(slots).length > 0) {
73
- throw new TypeError(`Slot not supported.`);
74
- }
75
- const widget = new WebWidgetRenderer(loader, {
76
- ...props,
77
- children: ""
78
- });
79
- const tag = widget.localName;
80
- const attrs = widget.attributes;
81
- const innerHTML = await widget.renderInnerHTMLToString().catch((err) => {
82
- const error = err instanceof Error ? err : new Error(String(err));
83
- console.error("[VueWidget] Rendering error:", error);
84
- return error;
85
- });
86
- if (innerHTML instanceof Error) {
87
- return () => errorFallback;
88
- }
89
- if (IS_CLIENT) {
90
- await customElements.whenDefined(tag);
91
- }
92
- const data = attrs.data;
93
- delete attrs.data;
94
- return () => {
95
- const nodeProps = {
96
- ...attrs,
97
- ...IS_CLIENT ? { "^data": data } : { data },
98
- ...!IS_CLIENT ? { innerHTML } : null
99
- };
100
- return h(tag, nodeProps);
101
- };
102
- }
103
- });
104
- function resolveFallback(fallback) {
105
- var _a;
106
- if (fallback !== null && typeof fallback === "object" && !("__v_isVNode" in fallback) && ("pending" in fallback || "error" in fallback)) {
107
- const obj = fallback;
108
- return {
109
- pendingFallback: obj.pending,
110
- errorFallback: (_a = obj.error) != null ? _a : obj.pending
111
- };
112
- }
113
- return {
114
- pendingFallback: fallback,
115
- errorFallback: fallback
116
- };
117
- }
118
- function container(loader, options = {}) {
119
- return defineComponent({
120
- name: "VueWidget",
121
- inheritAttrs: false,
122
- props: {
123
- widget: {
124
- type: Object,
125
- default: () => ({})
126
- }
127
- },
128
- setup({ widget }, { slots }) {
129
- var _a, _b;
130
- const {
131
- fallback,
132
- loading = (_a = options.loading) != null ? _a : "lazy",
133
- serverOnly,
134
- clientOnly
135
- } = widget;
136
- const { pendingFallback, errorFallback } = resolveFallback(fallback);
137
- const renderStage = serverOnly ? "server" : clientOnly ? "client" : options.renderStage;
138
- const data = useAttrs();
139
- if (clientOnly && !IS_CLIENT && pendingFallback) {
140
- const renderer = new WebWidgetRenderer(loader, {
141
- ...options,
142
- children: "",
143
- data,
144
- loading,
145
- renderStage,
146
- renderTarget: (_b = options.renderTarget) != null ? _b : "light"
147
- });
148
- return () => h(
149
- renderer.localName,
150
- renderer.attributes,
151
- h(
152
- renderer.pendingLocalName,
153
- {
154
- "aria-busy": "true",
155
- style: { display: "contents" }
156
- },
157
- pendingFallback
158
- )
159
- );
160
- }
161
- const error = ref(null);
162
- onErrorCaptured((err) => {
163
- error.value = err;
164
- return false;
165
- });
166
- return () => {
167
- var _a2;
168
- if (error.value && errorFallback) {
169
- return errorFallback;
170
- }
171
- return h(
172
- Suspense,
173
- {},
174
- {
175
- default: h(
176
- WebWidget,
177
- {
178
- ...options,
179
- data,
180
- errorFallback,
181
- loader,
182
- loading,
183
- renderStage,
184
- renderTarget: (_a2 = options.renderTarget) != null ? _a2 : "light"
185
- },
186
- slots
187
- ),
188
- fallback: pendingFallback
189
- }
190
- );
191
- };
192
- }
193
- });
194
- }
195
-
196
- export {
197
- installErrorHandler,
198
- resolveFallback,
199
- container
200
- };
@@ -1,87 +0,0 @@
1
- import { WebWidgetRendererOptions, Loader } from '@web-widget/web-widget';
2
- import { ExtractWidgetProps } from '@web-widget/schema';
3
- import { DefineComponent, VNode, App, Component } from 'vue';
4
-
5
- /**
6
- * A Vue component wrapping a widget, with props `T` plus container config.
7
- */
8
- type VueWidgetComponent<T = unknown> = DefineComponent<T & {
9
- widget?: WidgetContainerConfig;
10
- }>;
11
- interface DefineWebWidgetOptions {
12
- base?: WebWidgetRendererOptions['base'];
13
- import?: WebWidgetRendererOptions['import'];
14
- loading?: WebWidgetRendererOptions['loading'];
15
- name?: WebWidgetRendererOptions['name'];
16
- renderStage?: WebWidgetRendererOptions['renderStage'];
17
- renderTarget?: WebWidgetRendererOptions['renderTarget'];
18
- }
19
- type WidgetFallback = VNode | {
20
- pending?: VNode;
21
- error?: VNode;
22
- };
23
- /**
24
- * Resolve a WidgetFallback into separate pending and error VNodes.
25
- * - `VNode` — used for both pending and error.
26
- * - `{ pending?, error? }` — specify independently; `error` defaults to `pending`.
27
- */
28
- declare function resolveFallback(fallback: WidgetFallback | undefined): {
29
- pendingFallback: VNode;
30
- errorFallback: VNode;
31
- };
32
- interface WidgetContainerConfig {
33
- /**
34
- * Fallback UI for pending and error states.
35
- *
36
- * Only effective during server-side rendering: pending UI shows while the
37
- * widget module renders; error UI shows if rendering fails. Both are
38
- * serialized into the HTML stream — no client-side retry exists in the
39
- * islands architecture.
40
- * For `clientOnly`, pending UI is rendered inside the `<web-widget>` element
41
- * and removed immediately before its client mount begins.
42
- *
43
- * - `VNode` — used for both pending (Suspense) and error.
44
- * - `{ pending?, error? }` — specify independently; `error` defaults to `pending`.
45
- *
46
- * @example
47
- * // Simple: same UI for both states
48
- * <Widget :widget="{ fallback: h(Spinner) }" />
49
- *
50
- * // Differentiated: separate pending and error UI
51
- * <Widget :widget="{ fallback: { pending: h(Spinner), error: h(ErrorUI) } }" />
52
- */
53
- fallback?: WidgetFallback;
54
- /** Client-side module loading strategy: `'lazy'` loads on first render, `'eager'` on module parse, `'idle'` on browser idle. */
55
- loading?: WebWidgetRendererOptions['loading'];
56
- /** Widget renders only on the server (SSR), producing static HTML with no client-side mount. Mutually exclusive with `clientOnly`. */
57
- serverOnly?: true;
58
- /** Widget renders only on the client, producing no server HTML (empty placeholder until client mount). Mutually exclusive with `serverOnly`. */
59
- clientOnly?: true;
60
- }
61
- /**
62
- * Container function (WebWidgetAdapter protocol).
63
- *
64
- * Wraps a widget module loader into a Vue component with props type
65
- * inference from the source module's default export.
66
- *
67
- * @example
68
- * ```ts
69
- * import { container } from '@web-widget/vue/adapter';
70
- *
71
- * const Counter = container(() => import('./Counter@widget.vue'));
72
- * // ^? VueWidgetComponent<{ count: number }>
73
- * ```
74
- */
75
- declare function container<M>(loader: () => Promise<M>, options?: DefineWebWidgetOptions): VueWidgetComponent<ExtractWidgetProps<M>>;
76
- declare function container<Props>(loader: Loader, options?: DefineWebWidgetOptions): VueWidgetComponent<Props>;
77
-
78
- interface CreateVueRenderOptions {
79
- onCreatedApp?: (app: App<Element>, context: {
80
- container?: Element | DocumentFragment;
81
- data: any;
82
- progressive?: boolean;
83
- recovering?: boolean;
84
- }, component: Component, props: any) => Promise<void>;
85
- }
86
-
87
- export { type CreateVueRenderOptions as C, type DefineWebWidgetOptions as D, type VueWidgetComponent as V, type WidgetContainerConfig as W, type WidgetFallback as a, container as c, resolveFallback as r };