Skip to content

Commit f5569d0

Browse files
committed
[feat] webcontainer reload
1 parent 6f06bed commit f5569d0

File tree

2 files changed

+50
-14
lines changed

2 files changed

+50
-14
lines changed

src/routes/tutorial/[slug]/+page.svelte

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
selected
5656
});
5757
58-
/** @type {import('$lib/types').Adapter} */
58+
/** @type {import('$lib/types').Adapter | undefined} */
5959
let adapter;
6060
6161
/** @type {Record<string, string>}*/
@@ -104,7 +104,7 @@
104104
const contents = model.getValue();
105105
106106
if (!completing) {
107-
adapter.update([{ ...stub, contents }]);
107+
adapter?.update([{ ...stub, contents }]);
108108
}
109109
});
110110
@@ -120,6 +120,10 @@
120120
121121
completed = false;
122122
123+
load_webcontainer();
124+
});
125+
126+
async function load_webcontainer() {
123127
clearTimeout(timeout);
124128
loading = true;
125129
@@ -142,21 +146,35 @@
142146
143147
try {
144148
await new Promise((fulfil, reject) => {
149+
let called = false;
150+
145151
window.addEventListener('message', function handler(e) {
146-
if (e.origin !== adapter.base) return;
152+
if (e.origin !== adapter?.base) return;
147153
if (e.data.type === 'ping') {
148154
window.removeEventListener('message', handler);
155+
called = true;
149156
fulfil(undefined);
150157
}
158+
});
159+
160+
setTimeout(() => {
161+
if (!called && adapter) {
162+
// Updating the iframe too soon sometimes results in a blank screen,
163+
// so we try again after a short delay if we haven't heard back
164+
set_iframe_src(adapter.base);
165+
}
166+
}, 2000);
151167
152-
setTimeout(() => {
168+
setTimeout(() => {
169+
if (!called) {
153170
reject(new Error('Timed out'));
154-
}, 5000);
155-
});
171+
}
172+
}, 5000);
156173
});
157174
158175
expected = await get_transformed_modules(data.section.scope.prefix, Object.values(b));
159176
177+
const stubs = Object.values(data.section.a);
160178
await adapter.reset(stubs);
161179
const actual = await get_transformed_modules(data.section.scope.prefix, stubs);
162180
@@ -169,9 +187,10 @@
169187
loading = false;
170188
initial = false;
171189
} catch (e) {
190+
error = /** @type {Error} */ (e);
172191
console.error(e);
173192
}
174-
});
193+
}
175194
176195
/** @type {NodeJS.Timeout} */
177196
let timeout;
@@ -186,7 +205,7 @@
186205
187206
clearTimeout(timeout);
188207
timeout = setTimeout(() => {
189-
if (dev && !iframe) return;
208+
if ((dev && !iframe) || !adapter) return;
190209
191210
// we lost contact, refresh the page
192211
loading = true;
@@ -361,7 +380,7 @@
361380
}
362381
}
363382
364-
adapter.update(changes);
383+
adapter?.update(changes);
365384
completing = false;
366385
}}
367386
>
@@ -385,20 +404,32 @@
385404
{path}
386405
{loading}
387406
on:refresh={() => {
388-
set_iframe_src(adapter.base + path);
407+
if (adapter) {
408+
set_iframe_src(adapter.base + path);
409+
}
389410
}}
390411
on:change={(e) => {
391-
const url = new URL(e.detail.value, adapter.base);
392-
path = url.pathname + url.search + url.hash;
393-
set_iframe_src(adapter.base + path);
412+
if (adapter) {
413+
const url = new URL(e.detail.value, adapter.base);
414+
path = url.pathname + url.search + url.hash;
415+
set_iframe_src(adapter.base + path);
416+
}
394417
}}
395418
/>
396419
397420
<div class="content">
398421
<iframe bind:this={iframe} title="Output" />
399422
400423
{#if loading || error}
401-
<Loading {initial} {error} />
424+
<Loading
425+
{initial}
426+
{error}
427+
on:reload={async () => {
428+
await adapter?.destroy();
429+
adapter = undefined;
430+
load_webcontainer();
431+
}}
432+
/>
402433
{/if}
403434
</div>
404435
</section>

src/routes/tutorial/[slug]/Loading.svelte

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
<script>
2+
import { createEventDispatcher } from 'svelte';
3+
24
/** @type {boolean} */
35
export let initial;
46
@@ -17,11 +19,14 @@
1719
1820
return `<p>Failed to start WebContainer. You may need to enable third party cookies.</p><small>Error message: ${error.message}</small>`;
1921
}
22+
23+
const dispatch = createEventDispatcher();
2024
</script>
2125

2226
<div class="loading" class:error>
2327
{#if error}
2428
{@html get_error_message(error)}
29+
<button on:click={() => dispatch('reload')}>Reload</button>
2530
{:else}
2631
{#if initial}
2732
<p>initializing... this may take a few seconds</p>

0 commit comments

Comments
 (0)