vue-wswg-editor 0.0.17 → 0.0.19

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue-wswg-editor",
3
- "version": "0.0.17",
3
+ "version": "0.0.19",
4
4
  "type": "module",
5
5
  "main": "./dist/vue-wswg-editor.es.js",
6
6
  "module": "./dist/vue-wswg-editor.es.js",
@@ -21,12 +21,15 @@ import {
21
21
  sendSettingsOpen,
22
22
  sendScrollToBlock,
23
23
  handleIframeMessage,
24
+ sendInitIframeApp,
24
25
  } from "./messageHandler";
25
26
  import type { Block } from "../../types/Block";
26
27
  import { getIframeAppModuleUrl } from "./iframePreviewApp";
27
28
 
28
29
  // Get the iframe app module URL
29
30
  // This will be processed by the consuming app's Vite build
31
+ // Note: When the library is consumed as a bundled file, this URL may not resolve
32
+ // In that case, we'll use the postMessage fallback mechanism
30
33
  const iframeAppModuleUrl = getIframeAppModuleUrl();
31
34
 
32
35
  const props = defineProps<{
@@ -79,7 +82,9 @@ function onIframeLoad() {
79
82
  // Generate blob URL for iframe
80
83
  function createIframeSrc(): string {
81
84
  console.info("[parent] Creating iframe src, module URL:", iframeAppModuleUrl);
82
- const html = generateIframeHTML(iframeAppModuleUrl);
85
+ // Always pass undefined to use postMessage mechanism
86
+ // The module URL will be sent via postMessage after iframe loads
87
+ const html = generateIframeHTML(undefined);
83
88
  const blob = new Blob([html], { type: "text/html" });
84
89
  const blobUrl = URL.createObjectURL(blob);
85
90
  console.info("[parent] Iframe blob URL created:", blobUrl);
@@ -122,6 +127,28 @@ function setupMessageListener() {
122
127
 
123
128
  console.info("[parent] Received message from iframe:", event.data);
124
129
 
130
+ // Handle IFRAME_READY_FOR_APP - iframe is ready and requesting module URL
131
+ if (event.data && event.data.type === "IFRAME_READY_FOR_APP") {
132
+ console.info("[parent] IFRAME_READY_FOR_APP received, sending module URL");
133
+ if (iframeRef.value && iframeAppModuleUrl) {
134
+ sendInitIframeApp(iframeRef.value, iframeAppModuleUrl);
135
+ } else {
136
+ console.warn("[parent] Cannot send module URL - iframe ref or module URL not available");
137
+ }
138
+ return;
139
+ }
140
+
141
+ // Handle IFRAME_NEEDS_MODULE_URL - same as IFRAME_READY_FOR_APP
142
+ if (event.data && event.data.type === "IFRAME_NEEDS_MODULE_URL") {
143
+ console.info("[parent] IFRAME_NEEDS_MODULE_URL received, sending module URL");
144
+ if (iframeRef.value && iframeAppModuleUrl) {
145
+ sendInitIframeApp(iframeRef.value, iframeAppModuleUrl);
146
+ } else {
147
+ console.warn("[parent] Cannot send module URL - iframe ref or module URL not available");
148
+ }
149
+ return;
150
+ }
151
+
125
152
  handleIframeMessage(event, {
126
153
  onBlockClick: (_blockId: string, block: any) => {
127
154
  emit("click-block", block);
@@ -99,10 +99,10 @@ function extractParentStylesheets(): string {
99
99
  * This creates a standalone HTML page with a Vue app that will be loaded in the iframe
100
100
  * The Vue app uses PageRenderer to render blocks reactively
101
101
  *
102
- * @param iframeAppModuleUrl - URL to the iframe app module bundle
103
- * This should be obtained using import.meta.url from iframePreviewApp.ts
102
+ * Note: The module URL is now sent via postMessage after iframe loads
103
+ * This parameter is kept for backward compatibility but is not used
104
104
  */
105
- export function generateIframeHTML(iframeAppModuleUrl?: string): string {
105
+ export function generateIframeHTML(_iframeAppModuleUrl?: string): string {
106
106
  const parentStylesheets = extractParentStylesheets();
107
107
  const parentCSSVariables = extractParentCSSVariables();
108
108
  const vueCdnUrl = "https://unpkg.com/vue@3/dist/vue.esm-browser.js";
@@ -127,93 +127,74 @@ export function generateIframeHTML(iframeAppModuleUrl?: string): string {
127
127
  </script>`;
128
128
 
129
129
  // Generate script that loads Vue, vue-router, and initializes the iframe app
130
- // The import map above allows vue-router to resolve "vue" as a bare module specifier
131
- const appScript = iframeAppModuleUrl
132
- ? `<script type="module">
133
- console.info('[iframe] Script module starting...');
134
- console.info('[iframe] Module URL:', '${iframeAppModuleUrl}');
135
-
136
- import { createApp } from 'vue';
137
- console.info('[iframe] Vue imported successfully');
138
-
139
- import * as VueRouter from 'vue-router';
140
- console.info('[iframe] VueRouter imported successfully');
141
- // Make vue-router available globally so it can be accessed in the iframe app
142
- window.VueRouter = VueRouter;
143
-
144
- console.info('[iframe] Attempting to import createIframeApp from:', '${iframeAppModuleUrl}');
145
- import { createIframeApp } from '${iframeAppModuleUrl}';
146
- console.info('[iframe] createIframeApp imported successfully');
147
-
148
- const appEl = document.getElementById('app');
149
- console.info('[iframe] App element found:', appEl);
150
- if (appEl) {
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);
130
+ // Always use postMessage fallback mechanism since module URLs may not resolve when bundled
131
+ const appScript = `<script type="module">
132
+ console.info('[iframe] Script module starting...');
133
+
134
+ import { createApp } from 'vue';
135
+ console.info('[iframe] Vue imported successfully');
136
+
137
+ import * as VueRouter from 'vue-router';
138
+ console.info('[iframe] VueRouter imported successfully');
139
+ // Make vue-router available globally so it can be accessed in the iframe app
140
+ window.VueRouter = VueRouter;
141
+
142
+ let appInitialized = false;
143
+
144
+ // Always use postMessage mechanism to get the module URL
145
+ // This works whether the library is consumed as source or bundled
146
+ window.addEventListener('message', async (event) => {
147
+ console.info('[iframe] Received message:', event.data);
148
+ if (event.data.type === 'INIT_IFRAME_APP' && event.data.moduleUrl && !appInitialized) {
149
+ appInitialized = true;
150
+ console.info('[iframe] Initializing app with module URL:', event.data.moduleUrl);
151
+ try {
152
+ const { createIframeApp } = await import(event.data.moduleUrl);
153
+ console.info('[iframe] createIframeApp imported successfully');
154
+ const appEl = document.getElementById('app');
155
+ console.info('[iframe] App element found:', appEl);
156
+ if (appEl) {
157
+ console.info('[iframe] Calling createIframeApp...');
158
+ createIframeApp(appEl).then(() => {
159
+ console.info('[iframe] createIframeApp completed successfully');
160
+ }).catch(error => {
161
+ console.error('[iframe] createIframeApp failed:', error);
162
+ console.error('[iframe] Error stack:', error.stack);
163
+ // Fallback: create minimal Vue app
164
+ const appEl = document.getElementById('app');
165
+ if (appEl) {
166
+ console.info('[iframe] Creating fallback Vue app after error');
167
+ createApp({
168
+ template: '<div class="p-4">Error loading preview. Check console for details.</div>'
169
+ }).mount(appEl);
170
+ }
171
+ });
172
+ } else {
173
+ console.error('[iframe] App element not found!');
174
+ }
175
+ } catch (error) {
176
+ console.error('[iframe] Failed to load iframe app module:', error);
156
177
  console.error('[iframe] Error stack:', error.stack);
157
- });
158
- } else {
159
- console.error('[iframe] App element (#app) not found!');
160
- }
161
- </script>`
162
- : `<script type="module">
163
- // Fallback: Wait for parent to send module URL via postMessage
164
- console.info('[iframe] Fallback script module starting...');
165
- import { createApp } from 'vue';
166
- console.info('[iframe] Vue imported successfully (fallback)');
167
- import * as VueRouter from 'vue-router';
168
- console.info('[iframe] VueRouter imported successfully (fallback)');
169
- // Make vue-router available globally so it can be imported in the iframe app
170
- window.VueRouter = VueRouter;
171
-
172
- let appInitialized = false;
173
-
174
- window.addEventListener('message', async (event) => {
175
- console.info('[iframe] Received message:', event.data);
176
- if (event.data.type === 'INIT_IFRAME_APP' && event.data.moduleUrl && !appInitialized) {
177
- appInitialized = true;
178
- console.info('[iframe] Initializing app with module URL:', event.data.moduleUrl);
179
- try {
180
- const { createIframeApp } = await import(event.data.moduleUrl);
181
- console.info('[iframe] createIframeApp imported successfully (fallback)');
182
- const appEl = document.getElementById('app');
183
- console.info('[iframe] App element found (fallback):', appEl);
184
- if (appEl) {
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)!');
193
- }
194
- } catch (error) {
195
- console.error('[iframe] Failed to load iframe app module:', error);
196
- console.error('[iframe] Error stack:', error.stack);
197
- // Fallback: create minimal Vue app
198
- const appEl = document.getElementById('app');
199
- if (appEl) {
200
- console.info('[iframe] Creating fallback Vue app');
201
- createApp({
202
- template: '<div class="p-4">Loading preview...</div>'
203
- }).mount(appEl);
204
- }
178
+ // Fallback: create minimal Vue app
179
+ const appEl = document.getElementById('app');
180
+ if (appEl) {
181
+ console.info('[iframe] Creating fallback Vue app');
182
+ createApp({
183
+ template: '<div class="p-4">Loading preview...</div>'
184
+ }).mount(appEl);
205
185
  }
206
186
  }
207
- });
208
-
209
- // Notify parent that we're ready to receive module URL
210
- if (window.parent) {
211
- console.info('[iframe] Notifying parent that iframe is ready for app');
212
- window.parent.postMessage({ type: 'IFRAME_READY_FOR_APP' }, '*');
213
- } else {
214
- console.warn('[iframe] window.parent is not available');
215
187
  }
216
- </script>`;
188
+ });
189
+
190
+ // Notify parent that we're ready to receive module URL
191
+ if (window.parent) {
192
+ console.info('[iframe] Notifying parent that iframe is ready for app');
193
+ window.parent.postMessage({ type: 'IFRAME_READY_FOR_APP' }, '*');
194
+ } else {
195
+ console.warn('[iframe] window.parent is not available');
196
+ }
197
+ </script>`;
217
198
 
218
199
  return `<!DOCTYPE html>
219
200
  <html lang="en">
@@ -149,6 +149,25 @@ export function sendScrollToBlock(iframe: HTMLIFrameElement | null, blockId: str
149
149
  sendToIframe(iframe, message);
150
150
  }
151
151
 
152
+ /**
153
+ * Send module URL to iframe for initialization
154
+ * Used when iframe requests the module URL via postMessage
155
+ */
156
+ export function sendInitIframeApp(iframe: HTMLIFrameElement | null, moduleUrl: string): void {
157
+ if (!iframe || !iframe.contentWindow) {
158
+ console.warn("[parent] Cannot send INIT_IFRAME_APP: iframe not ready");
159
+ return;
160
+ }
161
+
162
+ try {
163
+ console.info("[parent] Sending INIT_IFRAME_APP with module URL:", moduleUrl);
164
+ iframe.contentWindow.postMessage({ type: "INIT_IFRAME_APP", moduleUrl }, "*");
165
+ console.info("[parent] INIT_IFRAME_APP message sent successfully");
166
+ } catch (error) {
167
+ console.error("[parent] Error sending INIT_IFRAME_APP message:", error);
168
+ }
169
+ }
170
+
152
171
  /**
153
172
  * Validate incoming message from iframe
154
173
  */