vue-wswg-editor 0.0.15 → 0.0.16
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/style.css +1 -1
- package/dist/vue-wswg-editor.es.js +1037 -944
- package/package.json +7 -1
- package/src/components/IframePreview/IframePreview.vue +59 -5
- package/src/components/IframePreview/iframeContent.ts +38 -4
- package/src/components/IframePreview/iframePreviewApp.ts +66 -8
- package/src/components/IframePreview/messageHandler.ts +6 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vue-wswg-editor",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/vue-wswg-editor.es.js",
|
|
6
6
|
"module": "./dist/vue-wswg-editor.es.js",
|
|
@@ -88,10 +88,16 @@
|
|
|
88
88
|
"vite": "^5.4.19",
|
|
89
89
|
"vitepress": "^1.6.4",
|
|
90
90
|
"vitest": "^2.1.9",
|
|
91
|
+
"vue-router": "^4.0.0",
|
|
91
92
|
"vue-tsc": "^2.2.12",
|
|
92
93
|
"yup": "^1.7.1"
|
|
93
94
|
},
|
|
94
95
|
"peerDependencies": {
|
|
95
96
|
"vue": "^3.4.0"
|
|
97
|
+
},
|
|
98
|
+
"peerDependenciesMeta": {
|
|
99
|
+
"vue-router": {
|
|
100
|
+
"optional": true
|
|
101
|
+
}
|
|
96
102
|
}
|
|
97
103
|
}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div ref="containerRef" class="iframe-preview-container">
|
|
3
|
-
<iframe
|
|
3
|
+
<iframe
|
|
4
|
+
ref="iframeRef"
|
|
5
|
+
title="Page preview"
|
|
6
|
+
:src="iframeSrc"
|
|
7
|
+
class="iframe-preview"
|
|
8
|
+
frameborder="0"
|
|
9
|
+
@load="onIframeLoad"
|
|
10
|
+
></iframe>
|
|
4
11
|
</div>
|
|
5
12
|
</template>
|
|
6
13
|
|
|
@@ -50,19 +57,54 @@ const iframeSrc = ref<string>("");
|
|
|
50
57
|
const blocksKey = computed(() => props.blocksKey || "blocks");
|
|
51
58
|
const settingsKey = computed(() => props.settingsKey || "settings");
|
|
52
59
|
|
|
60
|
+
// Handle iframe load event
|
|
61
|
+
function onIframeLoad() {
|
|
62
|
+
console.info("[parent] Iframe load event fired");
|
|
63
|
+
console.info("[parent] Iframe ref:", iframeRef.value);
|
|
64
|
+
console.info("[parent] Iframe contentWindow:", iframeRef.value?.contentWindow);
|
|
65
|
+
if (iframeRef.value?.contentWindow) {
|
|
66
|
+
try {
|
|
67
|
+
console.info("[parent] Iframe document:", iframeRef.value.contentWindow.document);
|
|
68
|
+
console.info("[parent] Iframe document body:", iframeRef.value.contentWindow.document.body);
|
|
69
|
+
console.info(
|
|
70
|
+
"[parent] Iframe document body innerHTML length:",
|
|
71
|
+
iframeRef.value.contentWindow.document.body.innerHTML.length
|
|
72
|
+
);
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.info("[parent] Cannot access iframe document (cross-origin?):", error);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
53
79
|
// Generate blob URL for iframe
|
|
54
80
|
function createIframeSrc(): string {
|
|
81
|
+
console.info("[parent] Creating iframe src, module URL:", iframeAppModuleUrl);
|
|
55
82
|
const html = generateIframeHTML(iframeAppModuleUrl);
|
|
56
83
|
const blob = new Blob([html], { type: "text/html" });
|
|
57
|
-
|
|
84
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
85
|
+
console.info("[parent] Iframe blob URL created:", blobUrl);
|
|
86
|
+
return blobUrl;
|
|
58
87
|
}
|
|
59
88
|
|
|
60
89
|
// Update iframe content - send pageData to Vue app in iframe
|
|
61
90
|
async function updateIframeContent() {
|
|
62
|
-
|
|
63
|
-
|
|
91
|
+
console.info("[parent] updateIframeContent called", {
|
|
92
|
+
hasIframeRef: !!iframeRef.value,
|
|
93
|
+
iframeReady: iframeReady.value,
|
|
94
|
+
hasPageData: !!props.pageData,
|
|
95
|
+
hasBlocks: !!(props.pageData && props.pageData[blocksKey.value]),
|
|
96
|
+
});
|
|
97
|
+
if (!iframeRef.value || !iframeReady.value) {
|
|
98
|
+
console.info("[parent] Skipping update - iframe not ready");
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (!props.pageData || !props.pageData[blocksKey.value]) {
|
|
102
|
+
console.info("[parent] Skipping update - no pageData or blocks");
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
64
105
|
|
|
65
106
|
await nextTick();
|
|
107
|
+
console.info("[parent] Sending pageData update to iframe");
|
|
66
108
|
sendPageDataUpdate(iframeRef.value, props.pageData, blocksKey.value, settingsKey.value, props.theme || "default");
|
|
67
109
|
}
|
|
68
110
|
|
|
@@ -70,9 +112,15 @@ async function updateIframeContent() {
|
|
|
70
112
|
let messageListener: ((event: MessageEvent) => void) | null = null;
|
|
71
113
|
|
|
72
114
|
function setupMessageListener() {
|
|
115
|
+
console.info("[parent] Setting up message listener");
|
|
73
116
|
messageListener = (event: MessageEvent) => {
|
|
74
117
|
// Only handle messages from our iframe
|
|
75
|
-
if (event.source !== iframeRef.value?.contentWindow)
|
|
118
|
+
if (event.source !== iframeRef.value?.contentWindow) {
|
|
119
|
+
console.info("[parent] Ignoring message from different source");
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
console.info("[parent] Received message from iframe:", event.data);
|
|
76
124
|
|
|
77
125
|
handleIframeMessage(event, {
|
|
78
126
|
onBlockClick: (_blockId: string, block: any) => {
|
|
@@ -91,12 +139,15 @@ function setupMessageListener() {
|
|
|
91
139
|
emit("click-partial", partialValue);
|
|
92
140
|
},
|
|
93
141
|
onIframeReady: () => {
|
|
142
|
+
console.info("[parent] IFRAME_READY received, setting iframeReady to true");
|
|
94
143
|
iframeReady.value = true;
|
|
95
144
|
// Wait a bit for iframe Vue app to be fully ready
|
|
96
145
|
setTimeout(() => {
|
|
146
|
+
console.info("[parent] Timeout completed, calling updateIframeContent");
|
|
97
147
|
updateIframeContent();
|
|
98
148
|
// Send initial settingsOpen state
|
|
99
149
|
if (iframeRef.value && props.settingsOpen !== undefined) {
|
|
150
|
+
console.info("[parent] Sending initial settingsOpen state");
|
|
100
151
|
sendSettingsOpen(iframeRef.value, props.settingsOpen);
|
|
101
152
|
}
|
|
102
153
|
}, 100);
|
|
@@ -105,6 +156,7 @@ function setupMessageListener() {
|
|
|
105
156
|
};
|
|
106
157
|
|
|
107
158
|
window.addEventListener("message", messageListener);
|
|
159
|
+
console.info("[parent] Message listener added");
|
|
108
160
|
}
|
|
109
161
|
|
|
110
162
|
function cleanupMessageListener() {
|
|
@@ -160,7 +212,9 @@ watch(
|
|
|
160
212
|
);
|
|
161
213
|
|
|
162
214
|
onMounted(() => {
|
|
215
|
+
console.info("[parent] IframePreview component mounted");
|
|
163
216
|
iframeSrc.value = createIframeSrc();
|
|
217
|
+
console.info("[parent] Iframe src set:", iframeSrc.value);
|
|
164
218
|
setupMessageListener();
|
|
165
219
|
});
|
|
166
220
|
|
|
@@ -130,43 +130,74 @@ export function generateIframeHTML(iframeAppModuleUrl?: string): string {
|
|
|
130
130
|
// The import map above allows vue-router to resolve "vue" as a bare module specifier
|
|
131
131
|
const appScript = iframeAppModuleUrl
|
|
132
132
|
? `<script type="module">
|
|
133
|
+
console.info('[iframe] Script module starting...');
|
|
134
|
+
console.info('[iframe] Module URL:', '${iframeAppModuleUrl}');
|
|
135
|
+
|
|
133
136
|
import { createApp } from 'vue';
|
|
137
|
+
console.info('[iframe] Vue imported successfully');
|
|
138
|
+
|
|
134
139
|
import * as VueRouter from 'vue-router';
|
|
140
|
+
console.info('[iframe] VueRouter imported successfully');
|
|
135
141
|
// Make vue-router available globally so it can be accessed in the iframe app
|
|
136
142
|
window.VueRouter = VueRouter;
|
|
137
143
|
|
|
144
|
+
console.info('[iframe] Attempting to import createIframeApp from:', '${iframeAppModuleUrl}');
|
|
138
145
|
import { createIframeApp } from '${iframeAppModuleUrl}';
|
|
146
|
+
console.info('[iframe] createIframeApp imported successfully');
|
|
139
147
|
|
|
140
148
|
const appEl = document.getElementById('app');
|
|
149
|
+
console.info('[iframe] App element found:', appEl);
|
|
141
150
|
if (appEl) {
|
|
142
|
-
|
|
143
|
-
|
|
151
|
+
console.info('[iframe] Calling createIframeApp...');
|
|
152
|
+
createIframeApp(appEl).then(() => {
|
|
153
|
+
console.info('[iframe] createIframeApp completed successfully');
|
|
154
|
+
}).catch(error => {
|
|
155
|
+
console.error('[iframe] Failed to create iframe app:', error);
|
|
156
|
+
console.error('[iframe] Error stack:', error.stack);
|
|
144
157
|
});
|
|
158
|
+
} else {
|
|
159
|
+
console.error('[iframe] App element (#app) not found!');
|
|
145
160
|
}
|
|
146
161
|
</script>`
|
|
147
162
|
: `<script type="module">
|
|
148
163
|
// Fallback: Wait for parent to send module URL via postMessage
|
|
164
|
+
console.info('[iframe] Fallback script module starting...');
|
|
149
165
|
import { createApp } from 'vue';
|
|
166
|
+
console.info('[iframe] Vue imported successfully (fallback)');
|
|
150
167
|
import * as VueRouter from 'vue-router';
|
|
168
|
+
console.info('[iframe] VueRouter imported successfully (fallback)');
|
|
151
169
|
// Make vue-router available globally so it can be imported in the iframe app
|
|
152
170
|
window.VueRouter = VueRouter;
|
|
153
171
|
|
|
154
172
|
let appInitialized = false;
|
|
155
173
|
|
|
156
174
|
window.addEventListener('message', async (event) => {
|
|
175
|
+
console.info('[iframe] Received message:', event.data);
|
|
157
176
|
if (event.data.type === 'INIT_IFRAME_APP' && event.data.moduleUrl && !appInitialized) {
|
|
158
177
|
appInitialized = true;
|
|
178
|
+
console.info('[iframe] Initializing app with module URL:', event.data.moduleUrl);
|
|
159
179
|
try {
|
|
160
180
|
const { createIframeApp } = await import(event.data.moduleUrl);
|
|
181
|
+
console.info('[iframe] createIframeApp imported successfully (fallback)');
|
|
161
182
|
const appEl = document.getElementById('app');
|
|
183
|
+
console.info('[iframe] App element found (fallback):', appEl);
|
|
162
184
|
if (appEl) {
|
|
163
|
-
createIframeApp(
|
|
185
|
+
console.info('[iframe] Calling createIframeApp (fallback)...');
|
|
186
|
+
createIframeApp(appEl).then(() => {
|
|
187
|
+
console.info('[iframe] createIframeApp completed successfully (fallback)');
|
|
188
|
+
}).catch(error => {
|
|
189
|
+
console.error('[iframe] createIframeApp failed (fallback):', error);
|
|
190
|
+
});
|
|
191
|
+
} else {
|
|
192
|
+
console.error('[iframe] App element not found (fallback)!');
|
|
164
193
|
}
|
|
165
194
|
} catch (error) {
|
|
166
|
-
console.error('Failed to load iframe app module:', error);
|
|
195
|
+
console.error('[iframe] Failed to load iframe app module:', error);
|
|
196
|
+
console.error('[iframe] Error stack:', error.stack);
|
|
167
197
|
// Fallback: create minimal Vue app
|
|
168
198
|
const appEl = document.getElementById('app');
|
|
169
199
|
if (appEl) {
|
|
200
|
+
console.info('[iframe] Creating fallback Vue app');
|
|
170
201
|
createApp({
|
|
171
202
|
template: '<div class="p-4">Loading preview...</div>'
|
|
172
203
|
}).mount(appEl);
|
|
@@ -177,7 +208,10 @@ export function generateIframeHTML(iframeAppModuleUrl?: string): string {
|
|
|
177
208
|
|
|
178
209
|
// Notify parent that we're ready to receive module URL
|
|
179
210
|
if (window.parent) {
|
|
211
|
+
console.info('[iframe] Notifying parent that iframe is ready for app');
|
|
180
212
|
window.parent.postMessage({ type: 'IFRAME_READY_FOR_APP' }, '*');
|
|
213
|
+
} else {
|
|
214
|
+
console.warn('[iframe] window.parent is not available');
|
|
181
215
|
}
|
|
182
216
|
</script>`;
|
|
183
217
|
|
|
@@ -45,6 +45,9 @@ export interface IframeAppCallbacks {
|
|
|
45
45
|
* Create and mount the Vue app for the iframe preview
|
|
46
46
|
*/
|
|
47
47
|
export async function createIframeApp(container: HTMLElement): Promise<App> {
|
|
48
|
+
console.info("[iframe] createIframeApp called with container:", container);
|
|
49
|
+
console.info("[iframe] Container element:", container.tagName, container.id, container.className);
|
|
50
|
+
|
|
48
51
|
// State
|
|
49
52
|
const pageData = ref<Record<string, any> | null>(null);
|
|
50
53
|
const activeBlock = ref<Block | null>(null);
|
|
@@ -53,6 +56,7 @@ export async function createIframeApp(container: HTMLElement): Promise<App> {
|
|
|
53
56
|
const blocksKey = ref<string>("blocks");
|
|
54
57
|
const settingsKey = ref<string>("settings");
|
|
55
58
|
const theme = ref<string>("default");
|
|
59
|
+
console.info("[iframe] State initialized");
|
|
56
60
|
// Serialize data for postMessage (handles Vue reactive proxies)
|
|
57
61
|
function serializeForPostMessage(data: any): any {
|
|
58
62
|
try {
|
|
@@ -75,14 +79,23 @@ export async function createIframeApp(container: HTMLElement): Promise<App> {
|
|
|
75
79
|
}
|
|
76
80
|
|
|
77
81
|
// Handle messages from parent
|
|
82
|
+
console.info("[iframe] Setting up message listener");
|
|
78
83
|
window.addEventListener("message", (event: MessageEvent) => {
|
|
79
84
|
const msg = event.data;
|
|
85
|
+
console.info("[iframe] Received message:", msg?.type, msg);
|
|
80
86
|
if (!msg || !msg.type) return;
|
|
81
87
|
|
|
82
88
|
switch (msg.type) {
|
|
83
89
|
case "UPDATE_PAGE_DATA":
|
|
90
|
+
console.info("[iframe] UPDATE_PAGE_DATA received", {
|
|
91
|
+
hasPageData: !!msg.pageData,
|
|
92
|
+
blocksKey: msg.blocksKey,
|
|
93
|
+
settingsKey: msg.settingsKey,
|
|
94
|
+
theme: msg.theme,
|
|
95
|
+
});
|
|
84
96
|
if (msg.pageData) {
|
|
85
97
|
pageData.value = msg.pageData;
|
|
98
|
+
console.info("[iframe] pageData updated:", pageData.value);
|
|
86
99
|
}
|
|
87
100
|
if (msg.blocksKey) {
|
|
88
101
|
blocksKey.value = msg.blocksKey;
|
|
@@ -114,25 +127,36 @@ export async function createIframeApp(container: HTMLElement): Promise<App> {
|
|
|
114
127
|
});
|
|
115
128
|
|
|
116
129
|
// Create Vue app using render function (since we're using runtime-only Vue)
|
|
130
|
+
console.info("[iframe] Creating Vue app...");
|
|
117
131
|
const app = createApp({
|
|
118
132
|
components: {
|
|
119
133
|
EditorPageRenderer,
|
|
120
134
|
},
|
|
121
135
|
setup() {
|
|
136
|
+
console.info("[iframe] Vue app setup() called");
|
|
122
137
|
// Ensure PageRenderer has time to load blocks before rendering
|
|
123
138
|
const isPageReady = ref(false);
|
|
124
139
|
|
|
125
140
|
// Watch for pageData changes
|
|
141
|
+
console.info("[iframe] Setting up pageData watcher");
|
|
126
142
|
watch(
|
|
127
143
|
() => pageData.value,
|
|
128
144
|
async (newPageData) => {
|
|
145
|
+
console.info("[iframe] pageData watcher triggered:", {
|
|
146
|
+
hasNewPageData: !!newPageData,
|
|
147
|
+
blocksKey: blocksKey.value,
|
|
148
|
+
hasBlocks: !!(newPageData && newPageData[blocksKey.value]),
|
|
149
|
+
});
|
|
129
150
|
if (newPageData && newPageData[blocksKey.value]) {
|
|
130
151
|
// Give PageRenderer time to load block modules
|
|
131
152
|
// PageRenderer loads blocks in onBeforeMount, so we need to wait
|
|
153
|
+
console.info("[iframe] Waiting 200ms for PageRenderer to load blocks...");
|
|
132
154
|
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
133
155
|
isPageReady.value = true;
|
|
156
|
+
console.info("[iframe] isPageReady set to true");
|
|
134
157
|
} else {
|
|
135
158
|
isPageReady.value = false;
|
|
159
|
+
console.info("[iframe] isPageReady set to false (no pageData)");
|
|
136
160
|
}
|
|
137
161
|
},
|
|
138
162
|
{ immediate: true }
|
|
@@ -144,7 +168,15 @@ export async function createIframeApp(container: HTMLElement): Promise<App> {
|
|
|
144
168
|
const hasPageData = currentPageData && currentPageData[blocksKey.value];
|
|
145
169
|
const blocks = hasPageData && currentPageData ? currentPageData[blocksKey.value] : [];
|
|
146
170
|
|
|
171
|
+
console.info("[iframe] Render function called:", {
|
|
172
|
+
isPageReady: isPageReady.value,
|
|
173
|
+
hasPageData: !!currentPageData,
|
|
174
|
+
hasBlocks: hasPageData,
|
|
175
|
+
blocksCount: blocks?.length || 0,
|
|
176
|
+
});
|
|
177
|
+
|
|
147
178
|
if (isPageReady.value && currentPageData) {
|
|
179
|
+
console.info("[iframe] Rendering EditorPageRenderer");
|
|
148
180
|
return h(EditorPageRenderer, {
|
|
149
181
|
blocks: blocks,
|
|
150
182
|
layout: currentPageData[settingsKey.value]?.layout,
|
|
@@ -156,6 +188,7 @@ export async function createIframeApp(container: HTMLElement): Promise<App> {
|
|
|
156
188
|
theme: theme.value,
|
|
157
189
|
});
|
|
158
190
|
} else {
|
|
191
|
+
console.info("[iframe] Rendering loading state");
|
|
159
192
|
// Show loading state while PageRenderer loads blocks
|
|
160
193
|
return h("div", { class: "bg-white px-5 py-12 md:py-20" }, [
|
|
161
194
|
h("div", { class: "mx-auto max-w-md pb-7 text-center" }, [
|
|
@@ -199,17 +232,23 @@ export async function createIframeApp(container: HTMLElement): Promise<App> {
|
|
|
199
232
|
|
|
200
233
|
// Try to install Unhead plugin if available
|
|
201
234
|
// This is needed for layouts that use useHead from @vueuse/head
|
|
235
|
+
console.info("[iframe] Attempting to install @vueuse/head plugin...");
|
|
202
236
|
try {
|
|
203
237
|
// Dynamic import to check if @vueuse/head is available
|
|
204
238
|
// This module is externalized in vite.config.ts so it won't be bundled
|
|
205
239
|
const headModule = await dynamicImport("@vueuse/head");
|
|
206
240
|
if (headModule && typeof headModule.createHead === "function") {
|
|
241
|
+
console.info("[iframe] @vueuse/head found, installing plugin");
|
|
207
242
|
const head = headModule.createHead();
|
|
208
243
|
app.use(head);
|
|
244
|
+
console.info("[iframe] @vueuse/head plugin installed");
|
|
245
|
+
} else {
|
|
246
|
+
console.info("[iframe] @vueuse/head module found but createHead is not a function");
|
|
209
247
|
}
|
|
210
|
-
} catch {
|
|
248
|
+
} catch (error) {
|
|
211
249
|
// @vueuse/head not available - layouts using useHead will show warnings but won't break
|
|
212
250
|
// This is expected if the consuming app doesn't use @vueuse/head
|
|
251
|
+
console.info("[iframe] @vueuse/head not available (this is OK):", error);
|
|
213
252
|
}
|
|
214
253
|
|
|
215
254
|
// Try to use vue-router - first try from CDN, but components use consuming app's vue-router
|
|
@@ -217,25 +256,29 @@ export async function createIframeApp(container: HTMLElement): Promise<App> {
|
|
|
217
256
|
// with different Symbol keys. We need to use the same instance they're using.
|
|
218
257
|
// Try to import vue-router dynamically - this will use the consuming app's vue-router
|
|
219
258
|
// if it's available in the module resolution context
|
|
259
|
+
console.info("[iframe] Attempting to install vue-router...");
|
|
220
260
|
let VueRouter: any = null;
|
|
221
261
|
let routerInstalled = false;
|
|
222
262
|
|
|
223
263
|
try {
|
|
224
|
-
//
|
|
225
|
-
// when the library is consumed as source code
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
const routerModule = await import("vue-router");
|
|
264
|
+
// Use dynamic import helper to prevent static analysis
|
|
265
|
+
// This should resolve to the consuming app's vue-router when the library is consumed as source code
|
|
266
|
+
console.info("[iframe] Trying to import vue-router dynamically...");
|
|
267
|
+
const routerModule = await dynamicImport("vue-router");
|
|
229
268
|
VueRouter = routerModule;
|
|
230
|
-
|
|
269
|
+
console.info("[iframe] vue-router imported successfully:", !!VueRouter);
|
|
270
|
+
} catch (error) {
|
|
231
271
|
// Fallback to CDN version
|
|
272
|
+
console.info("[iframe] Dynamic import failed, trying CDN version:", error);
|
|
232
273
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
233
274
|
// @ts-ignore
|
|
234
275
|
VueRouter = typeof window !== "undefined" ? (window as any).VueRouter : null;
|
|
276
|
+
console.info("[iframe] VueRouter from window:", !!VueRouter);
|
|
235
277
|
}
|
|
236
278
|
|
|
237
279
|
if (VueRouter && typeof VueRouter.createRouter === "function") {
|
|
238
280
|
try {
|
|
281
|
+
console.info("[iframe] Creating vue-router instance...");
|
|
239
282
|
// Create a minimal router instance
|
|
240
283
|
const router = VueRouter.createRouter({
|
|
241
284
|
history: VueRouter.createMemoryHistory(),
|
|
@@ -250,6 +293,7 @@ export async function createIframeApp(container: HTMLElement): Promise<App> {
|
|
|
250
293
|
},
|
|
251
294
|
],
|
|
252
295
|
});
|
|
296
|
+
console.info("[iframe] Router created, setting up resolve override...");
|
|
253
297
|
|
|
254
298
|
// Store original resolve to call it first, then ensure matched array exists
|
|
255
299
|
const originalResolve = router.resolve.bind(router);
|
|
@@ -273,10 +317,13 @@ export async function createIframeApp(container: HTMLElement): Promise<App> {
|
|
|
273
317
|
|
|
274
318
|
// Install router BEFORE mounting - this provides the router injection
|
|
275
319
|
// The app.use() call should handle the Symbol keys automatically
|
|
320
|
+
console.info("[iframe] Installing router on app...");
|
|
276
321
|
app.use(router);
|
|
277
322
|
|
|
278
323
|
// Wait for router to be ready before mounting
|
|
324
|
+
console.info("[iframe] Waiting for router to be ready...");
|
|
279
325
|
await router.isReady();
|
|
326
|
+
console.info("[iframe] Router is ready");
|
|
280
327
|
|
|
281
328
|
// Ensure currentRoute has proper structure with matched array
|
|
282
329
|
// currentRoute.value is readonly, so we navigate to ensure route is properly resolved
|
|
@@ -285,23 +332,34 @@ export async function createIframeApp(container: HTMLElement): Promise<App> {
|
|
|
285
332
|
const currentRoute = router.currentRoute.value;
|
|
286
333
|
if (currentRoute && (!currentRoute.matched || currentRoute.matched.length === 0)) {
|
|
287
334
|
// Navigate to ensure route has proper matched array
|
|
335
|
+
console.info("[iframe] Navigating to / to ensure route has matched array");
|
|
288
336
|
await router.push("/");
|
|
289
337
|
}
|
|
290
338
|
|
|
291
339
|
routerInstalled = true;
|
|
292
|
-
|
|
340
|
+
console.info("[iframe] Router installed successfully");
|
|
341
|
+
} catch (error) {
|
|
293
342
|
// Fall through to mount without router
|
|
343
|
+
console.error("[iframe] Failed to install router:", error);
|
|
294
344
|
}
|
|
345
|
+
} else {
|
|
346
|
+
console.info("[iframe] VueRouter not available or createRouter is not a function");
|
|
295
347
|
}
|
|
296
348
|
|
|
297
349
|
if (!routerInstalled) {
|
|
298
350
|
// Router was not installed - RouterLink components will fail
|
|
299
351
|
console.warn("[iframe preview] Router was not installed - RouterLink components will fail");
|
|
300
352
|
}
|
|
353
|
+
|
|
301
354
|
// Mount the app
|
|
355
|
+
console.info("[iframe] Mounting app to container...");
|
|
356
|
+
console.info("[iframe] Container before mount:", container.innerHTML);
|
|
302
357
|
app.mount(container);
|
|
358
|
+
console.info("[iframe] App mounted successfully");
|
|
359
|
+
console.info("[iframe] Container after mount:", container.innerHTML);
|
|
303
360
|
|
|
304
361
|
// Notify parent that iframe is ready
|
|
362
|
+
console.info("[iframe] Sending IFRAME_READY message to parent");
|
|
305
363
|
sendToParent({ type: "IFRAME_READY" });
|
|
306
364
|
|
|
307
365
|
return app;
|
|
@@ -27,23 +27,26 @@ function serializeForPostMessage(data: any): any {
|
|
|
27
27
|
* Send a message to the iframe
|
|
28
28
|
*/
|
|
29
29
|
export function sendToIframe(iframe: HTMLIFrameElement | null, message: IframeMessage): void {
|
|
30
|
+
console.info("[parent] sendToIframe called:", message.type);
|
|
30
31
|
if (!iframe || !iframe.contentWindow) {
|
|
31
|
-
console.warn("Cannot send message: iframe not ready");
|
|
32
|
+
console.warn("[parent] Cannot send message: iframe not ready");
|
|
32
33
|
return;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
// Serialize message to handle Vue reactive proxies
|
|
36
37
|
const serializedMessage = serializeForPostMessage(message) as IframeMessage;
|
|
37
38
|
if (!serializedMessage) {
|
|
38
|
-
console.error("Failed to serialize message for postMessage");
|
|
39
|
+
console.error("[parent] Failed to serialize message for postMessage");
|
|
39
40
|
return;
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
// Security: Only send to same origin
|
|
43
44
|
try {
|
|
45
|
+
console.info("[parent] Posting message to iframe:", message.type, serializedMessage);
|
|
44
46
|
iframe.contentWindow.postMessage(serializedMessage, "*");
|
|
47
|
+
console.info("[parent] Message posted successfully");
|
|
45
48
|
} catch (error) {
|
|
46
|
-
console.error("Error sending message to iframe:", error);
|
|
49
|
+
console.error("[parent] Error sending message to iframe:", error);
|
|
47
50
|
}
|
|
48
51
|
}
|
|
49
52
|
|