Skip to content

Commit 508677a

Browse files
test: fix errors.
1 parent cedd79f commit 508677a

1 file changed

Lines changed: 69 additions & 9 deletions

File tree

src/modules/preview-runtime/iframe-preview-executor.js

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ const createIframeShellDocument = ({ channelId, parentOrigin, importMap }) => {
5454
5555
const __knightedState = {
5656
entrySpecifier: '',
57+
reactRoot: null,
58+
renderedNode: null,
5759
}
5860
5961
const __knightedRuntimeErrorFingerprints = new Set()
@@ -191,14 +193,20 @@ const createIframeShellDocument = ({ channelId, parentOrigin, importMap }) => {
191193
192194
__knightedApplyVisualConfig(config)
193195
194-
let runtimeRoot = document.getElementById('knighted-preview-runtime-root')
195-
if (!(runtimeRoot instanceof HTMLElement)) {
196-
runtimeRoot = document.createElement('div')
197-
runtimeRoot.id = 'knighted-preview-runtime-root'
198-
document.body.append(runtimeRoot)
196+
if (
197+
__knightedState.reactRoot &&
198+
typeof __knightedState.reactRoot.unmount === 'function'
199+
) {
200+
__knightedState.reactRoot.unmount()
201+
__knightedState.reactRoot = null
199202
}
200203
201-
runtimeRoot.replaceChildren()
204+
if (__knightedState.renderedNode instanceof Node) {
205+
__knightedState.renderedNode.remove()
206+
__knightedState.renderedNode = null
207+
}
208+
209+
document.querySelectorAll('knighted-preview-root').forEach(node => node.remove())
202210
203211
try {
204212
const entryModule = await import(entrySpecifier)
@@ -220,8 +228,10 @@ const createIframeShellDocument = ({ channelId, parentOrigin, importMap }) => {
220228
}
221229
222230
const host = document.createElement('knighted-preview-root')
223-
runtimeRoot.append(host)
231+
document.body.append(host)
224232
const root = createRoot(host)
233+
__knightedState.reactRoot = root
234+
__knightedState.renderedNode = host
225235
root.render(output)
226236
} else {
227237
const { jsx } = await import(runtimeSpecifiers.jsxDom)
@@ -231,7 +241,8 @@ const createIframeShellDocument = ({ channelId, parentOrigin, importMap }) => {
231241
throw new Error('Expected a function or const named App.')
232242
}
233243
234-
runtimeRoot.append(output)
244+
document.body.append(output)
245+
__knightedState.renderedNode = output
235246
}
236247
237248
__knightedEmit(__knightedMessageTypes.rendered)
@@ -336,12 +347,48 @@ export const createWorkspaceIframePreviewBridge = ({
336347
let active = true
337348
let ready = false
338349
let resolveReady = () => {}
350+
const readyWaiters = new Set()
339351
const readyPromise = new Promise(resolve => {
340352
resolveReady = resolve
341353
})
342354

343355
let pendingRender = null
344356

357+
const waitForReady = timeoutMs => {
358+
if (ready) {
359+
return Promise.resolve()
360+
}
361+
362+
if (!active) {
363+
return Promise.reject(new Error('Preview iframe bridge is not active.'))
364+
}
365+
366+
return new Promise((resolve, reject) => {
367+
const timer = setTimeout(() => {
368+
readyWaiters.delete(onDisposed)
369+
reject(new Error('Workspace preview iframe did not become ready before timeout.'))
370+
}, timeoutMs)
371+
372+
const onReady = () => {
373+
clearTimeout(timer)
374+
readyWaiters.delete(onDisposed)
375+
resolve()
376+
}
377+
378+
const onDisposed = error => {
379+
clearTimeout(timer)
380+
reject(
381+
error instanceof Error
382+
? error
383+
: new Error('Preview iframe bridge was disposed before readiness.'),
384+
)
385+
}
386+
387+
readyPromise.then(onReady)
388+
readyWaiters.add(onDisposed)
389+
})
390+
}
391+
345392
const cleanupPendingRender = (error = null) => {
346393
if (!pendingRender) {
347394
return
@@ -381,6 +428,10 @@ export const createWorkspaceIframePreviewBridge = ({
381428
return
382429
}
383430

431+
if (!iframe.contentWindow || event.source !== iframe.contentWindow) {
432+
return
433+
}
434+
384435
const data = event?.data
385436
if (!isPreviewProtocolMessage({ data, channelId })) {
386437
return
@@ -430,6 +481,15 @@ export const createWorkspaceIframePreviewBridge = ({
430481

431482
active = false
432483
window.removeEventListener('message', onMessage)
484+
if (readyWaiters.size > 0) {
485+
const disposeError = new Error(
486+
'Preview iframe bridge was disposed before readiness.',
487+
)
488+
for (const notifyDisposed of readyWaiters) {
489+
notifyDisposed(disposeError)
490+
}
491+
readyWaiters.clear()
492+
}
433493
if (pendingRender) {
434494
cleanupPendingRender(
435495
new Error('Preview iframe bridge disposed before render completed.'),
@@ -457,7 +517,7 @@ export const createWorkspaceIframePreviewBridge = ({
457517
throw new Error('Preview iframe render already in flight.')
458518
}
459519

460-
await readyPromise
520+
await waitForReady(timeoutMs)
461521

462522
return new Promise((resolve, reject) => {
463523
const timer = setTimeout(() => {

0 commit comments

Comments
 (0)