From 34125817f18ad776ebc5259de0d139a7e367aac2 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 8 Apr 2023 12:19:55 -0400 Subject: [PATCH 1/3] reinstate ping mechanism --- content/tutorial/common/src/__client.js | 17 +++++++++++++++++ src/routes/tutorial/[slug]/Output.svelte | 18 ++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/content/tutorial/common/src/__client.js b/content/tutorial/common/src/__client.js index 1a419ed0b..07c11012a 100644 --- a/content/tutorial/common/src/__client.js +++ b/content/tutorial/common/src/__client.js @@ -1,3 +1,19 @@ +// Hack into the alert that's used in some tutorials and send a message prior to the alert, +// else the parent thinks we lost contact and wrongfully reloads the page. +// The drawback is that alert is no longer blocking, but no tutorial relies on this. +const alert = window.alert; +window.alert = (message) => { + parent.postMessage( + { + type: 'ping-pause' + }, + '*' + ); + setTimeout(() => { + alert(message); + }); +}; + window.addEventListener('message', async (e) => { if (e.data.type === 'fetch') { const names = e.data.names; @@ -123,6 +139,7 @@ const url_observer = new MutationObserver(() => { }); url_observer.observe(document, { subtree: true, childList: true, attributes: true }); +setInterval(ping, 100); ping(); if (import.meta.hot) { diff --git a/src/routes/tutorial/[slug]/Output.svelte b/src/routes/tutorial/[slug]/Output.svelte index 59b94af4e..2c68b20be 100644 --- a/src/routes/tutorial/[slug]/Output.svelte +++ b/src/routes/tutorial/[slug]/Output.svelte @@ -34,6 +34,13 @@ }; }); + afterNavigate(() => { + clearTimeout(timeout); + }); + + /** @type {any} */ + let timeout; + /** @param {MessageEvent} e */ async function handle_message(e) { if (e.origin !== $base) return; @@ -43,6 +50,17 @@ if (e.data.type === 'ping') { path = e.data.data.path ?? path; loading = false; + + clearTimeout(timeout); + timeout = setTimeout(() => { + if (dev && !iframe) return; + // we lost contact, refresh the page + loading = true; + set_iframe_src($base + path); + loading = false; + }, 1000); + } else if (e.data.type === 'ping-pause') { + clearTimeout(timeout); } else if (e.data.type === 'warnings') { warnings.update(($warnings) => ({ ...$warnings, From f08c1c9ff04022e14229fb85ccc9ecc1799a1078 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 8 Apr 2023 12:26:51 -0400 Subject: [PATCH 2/3] tidy up __client.js a bit --- content/tutorial/common/src/__client.js | 113 ++++++------------------ 1 file changed, 25 insertions(+), 88 deletions(-) diff --git a/content/tutorial/common/src/__client.js b/content/tutorial/common/src/__client.js index 07c11012a..f25479e2b 100644 --- a/content/tutorial/common/src/__client.js +++ b/content/tutorial/common/src/__client.js @@ -1,68 +1,19 @@ +function post(data) { + parent.postMessage(data, '*'); +} + // Hack into the alert that's used in some tutorials and send a message prior to the alert, // else the parent thinks we lost contact and wrongfully reloads the page. // The drawback is that alert is no longer blocking, but no tutorial relies on this. const alert = window.alert; window.alert = (message) => { - parent.postMessage( - { - type: 'ping-pause' - }, - '*' - ); + post({ type: 'ping-pause' }); + setTimeout(() => { alert(message); }); }; -window.addEventListener('message', async (e) => { - if (e.data.type === 'fetch') { - const names = e.data.names; - - const transformed = await Promise.all( - names.map(async (name) => { - const res = await fetch(name); - return { - name, - code: await res.text() - }; - }) - ); - - const css_files = []; - - for (const { name, code } of transformed) { - if ( - name.endsWith('.svelte') && - code.includes('svelte&type=style&lang.css') - ) { - css_files.push(name + '?svelte&type=style&lang.css'); - } - } - - if (css_files.length > 0) { - const css_transformed = await Promise.all( - css_files.map(async (name) => { - const res = await fetch(name); - return { - name, - code: await res.text() - }; - }) - ); - - transformed.push(...css_transformed); - } - - parent.postMessage( - { - type: 'fetch-result', - data: transformed - }, - '*' - ); - } -}); - let can_focus = false; window.addEventListener('pointerdown', (e) => { @@ -94,12 +45,7 @@ window.addEventListener('focusin', (e) => { if (e.target.tagName === 'BODY' && e.relatedTarget) return; // otherwise, broadcast an event that causes the editor to reclaim focus - parent.postMessage( - { - type: 'iframe_took_focus' - }, - '*' - ); + post({ type: 'iframe_took_focus' }); }); window.addEventListener('click', (e) => { @@ -119,47 +65,38 @@ window.addEventListener('click', (e) => { }); function ping() { - parent.postMessage( - { - type: 'ping', - data: { - path: location.pathname + location.search + location.hash - } - }, - '*' - ); + post({ + type: 'ping', + data: { + path: location.pathname + location.search + location.hash + } + }); } -let pre_url = location.href; +let previous_href = location.href; + const url_observer = new MutationObserver(() => { - if (location.href !== pre_url) { - pre_url = location.href; + if (location.href !== previous_href) { + previous_href = location.href; ping(); } }); -url_observer.observe(document, { subtree: true, childList: true, attributes: true }); + +url_observer.observe(document, { + subtree: true, + childList: true, + attributes: true +}); setInterval(ping, 100); ping(); if (import.meta.hot) { import.meta.hot.on('vite:beforeUpdate', (event) => { - parent.postMessage( - { - type: 'hmr', - data: event.updates - }, - '*' - ); + post({ type: 'hmr', data: event.updates }); }); import.meta.hot.on('svelte:warnings', (data) => { - parent.postMessage( - { - type: 'warnings', - data - }, - '*' - ); + post({ type: 'warnings', data }); }); } From d104084278f17a6ed39df77ba224bb447523b748 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 8 Apr 2023 12:38:46 -0400 Subject: [PATCH 3/3] fix 298 --- content/tutorial/common/src/__client.js | 47 ++++++++++++------------ src/routes/tutorial/[slug]/Output.svelte | 3 +- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/content/tutorial/common/src/__client.js b/content/tutorial/common/src/__client.js index f25479e2b..a6741586f 100644 --- a/content/tutorial/common/src/__client.js +++ b/content/tutorial/common/src/__client.js @@ -2,12 +2,23 @@ function post(data) { parent.postMessage(data, '*'); } +function ping() { + post({ + type: 'ping', + path: location.pathname + location.search + location.hash + }); +} + +function pause() { + post({ type: 'ping-pause' }); +} + // Hack into the alert that's used in some tutorials and send a message prior to the alert, // else the parent thinks we lost contact and wrongfully reloads the page. // The drawback is that alert is no longer blocking, but no tutorial relies on this. const alert = window.alert; window.alert = (message) => { - post({ type: 'ping-pause' }); + pause(); setTimeout(() => { alert(message); @@ -16,21 +27,10 @@ window.alert = (message) => { let can_focus = false; -window.addEventListener('pointerdown', (e) => { - can_focus = true; -}); - -window.addEventListener('pointerup', (e) => { - can_focus = false; -}); - -window.addEventListener('keydown', (e) => { - can_focus = true; -}); - -window.addEventListener('keyup', (e) => { - can_focus = false; -}); +window.addEventListener('pointerdown', (e) => can_focus = true); +window.addEventListener('pointerup', (e) => can_focus = false); +window.addEventListener('keydown', (e) => can_focus = true); +window.addEventListener('keyup', (e) => can_focus = false); /** * The iframe sometimes takes focus control in ways we can't prevent @@ -64,14 +64,13 @@ window.addEventListener('click', (e) => { } }); -function ping() { - post({ - type: 'ping', - data: { - path: location.pathname + location.search + location.hash - } - }); -} +window.addEventListener('visibilitychange', () => { + if (document.visibilityState === 'visible') { + ping(); + } else { + pause(); + } +}); let previous_href = location.href; diff --git a/src/routes/tutorial/[slug]/Output.svelte b/src/routes/tutorial/[slug]/Output.svelte index 2c68b20be..013661cb2 100644 --- a/src/routes/tutorial/[slug]/Output.svelte +++ b/src/routes/tutorial/[slug]/Output.svelte @@ -48,12 +48,13 @@ if (paused) return; if (e.data.type === 'ping') { - path = e.data.data.path ?? path; + path = e.data.path; loading = false; clearTimeout(timeout); timeout = setTimeout(() => { if (dev && !iframe) return; + // we lost contact, refresh the page loading = true; set_iframe_src($base + path);