From f0b82d9f98d28717a67d6a46ecea6a39a6ea06f3 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Wed, 9 Oct 2024 14:37:34 +0200 Subject: [PATCH 1/4] ensure full page reloads between SvelteKit tutorial and other pages (and vice versa) --- apps/svelte.dev/src/routes/+layout.svelte | 29 ++++++++++++++++--- .../src/routes/tutorial/[slug]/+page.svelte | 8 ++--- .../routes/tutorial/[slug]/adapter.svelte.ts | 7 +++-- .../src/routes/tutorial/[slug]/shared.ts | 7 +++++ 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/apps/svelte.dev/src/routes/+layout.svelte b/apps/svelte.dev/src/routes/+layout.svelte index 28bd34375d..b9759daa6e 100644 --- a/apps/svelte.dev/src/routes/+layout.svelte +++ b/apps/svelte.dev/src/routes/+layout.svelte @@ -1,15 +1,36 @@ - diff --git a/apps/svelte.dev/src/routes/tutorial/[slug]/+page.svelte b/apps/svelte.dev/src/routes/tutorial/[slug]/+page.svelte index 680e62ae73..5805f64800 100644 --- a/apps/svelte.dev/src/routes/tutorial/[slug]/+page.svelte +++ b/apps/svelte.dev/src/routes/tutorial/[slug]/+page.svelte @@ -19,7 +19,7 @@ selected_name, solution } from './state.js'; - import { text_files } from './shared'; + import { needs_webcontainers, text_files } from './shared'; import OutputRollup from './OutputRollup.svelte'; import { page } from '$app/stores'; @@ -317,10 +317,10 @@
- {#if /svelte$/.test($page.data.exercise.part.slug)} - - {:else} + {#if needs_webcontainers($page.data.exercise)} + {:else} + {/if}
diff --git a/apps/svelte.dev/src/routes/tutorial/[slug]/adapter.svelte.ts b/apps/svelte.dev/src/routes/tutorial/[slug]/adapter.svelte.ts index 0a86794fb4..b192b96d29 100644 --- a/apps/svelte.dev/src/routes/tutorial/[slug]/adapter.svelte.ts +++ b/apps/svelte.dev/src/routes/tutorial/[slug]/adapter.svelte.ts @@ -3,6 +3,7 @@ import { page } from '$app/stores'; import type { state as WCState } from '$lib/tutorial/adapters/webcontainer/index.svelte'; import type { state as RollupState } from '$lib/tutorial/adapters/rollup/index.svelte'; import type { Adapter, FileStub, Stub } from '$lib/tutorial'; +import { needs_webcontainers } from './shared'; let initial_load = true; let use_rollup = $state(true); @@ -35,9 +36,9 @@ export const adapter_state = new (class { if (browser) { page.subscribe(($page) => { - const slug = $page.data?.exercise?.part?.slug; - if (slug) { - use_rollup = /svelte$/.test(slug); + const exercise = $page.data?.exercise; + if (exercise) { + use_rollup = !needs_webcontainers(exercise); if (use_rollup) { load_rollup(); diff --git a/apps/svelte.dev/src/routes/tutorial/[slug]/shared.ts b/apps/svelte.dev/src/routes/tutorial/[slug]/shared.ts index 4d8905ec30..f15df53c9f 100644 --- a/apps/svelte.dev/src/routes/tutorial/[slug]/shared.ts +++ b/apps/svelte.dev/src/routes/tutorial/[slug]/shared.ts @@ -1,3 +1,5 @@ +import type { Exercise } from '$lib/tutorial'; + export const text_files = new Set([ '.svelte', '.txt', @@ -10,3 +12,8 @@ export const text_files = new Set([ '.md', '.env' ]); + +/** The SvelteKit tutorial needs web container technology */ +export function needs_webcontainers(exercise: Exercise | undefined) { + return !!exercise && /sveltekit$/.test(exercise.part?.slug); +} From 6ac87552b0c49aac13f0b5bb4896553ca0a0288c Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Wed, 9 Oct 2024 14:38:47 +0200 Subject: [PATCH 2/4] update docs --- apps/svelte.dev/README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/svelte.dev/README.md b/apps/svelte.dev/README.md index bf6c3c6ff7..9cfdd92815 100644 --- a/apps/svelte.dev/README.md +++ b/apps/svelte.dev/README.md @@ -15,9 +15,7 @@ Cross-Origin-Embedder-Policy: require-corp Cross-Origin-Opener-Policy: same-origin ``` -Because we're doing soft navigation between pages, these headers need to be set for all responses, not just the ones from `/tutorial`. - -The result of setting these headers is that the site can no longer embed URLs from other sites (like images from another domain) without those domains either having a `cross-origin-resource-policy: cross-origin` header (which most don't) or us adding the `crossorigin="anonymous"` attribute (or the experimental-only-working-in-chrome `credentialless` for iframes) to the elements that load those URLs. +The result of setting these headers is that the site can no longer embed URLs from other sites (like images from another domain) without those domains either having a `cross-origin-resource-policy: cross-origin` header (which most don't) or us adding the `crossorigin="anonymous"` attribute (or the experimental-only-working-in-chrome `credentialless` for iframes) to the elements that load those URLs. For this reason, navigations between the SvelteKit tutorial and other pages (and vice versa) are full page navigations so the headers don't interfere with the rest of the page. When writing content for the tutorial, you need to be aware of the differences of loading content: From 3f79d4ac0f73fbc79734892576469478b4b98102 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 9 Oct 2024 14:49:19 -0400 Subject: [PATCH 3/4] fix --- apps/svelte.dev/src/routes/+layout.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/svelte.dev/src/routes/+layout.svelte b/apps/svelte.dev/src/routes/+layout.svelte index b9759daa6e..f0f136d2b6 100644 --- a/apps/svelte.dev/src/routes/+layout.svelte +++ b/apps/svelte.dev/src/routes/+layout.svelte @@ -7,7 +7,7 @@ import { Search, SearchBox } from '@sveltejs/site-kit/search'; import { injectSpeedInsights } from '@vercel/speed-insights/sveltekit'; import { afterNavigate } from '$app/navigation'; - import { needs_webcontainers } from './tutorial/[slug]/shared'; + import { needs_webcontainers } from './tutorial/[...slug]/shared'; import type { Exercise } from '$lib/tutorial'; injectSpeedInsights(); From 58be8e9a83906bf18a93ec2c69d8d024d6b95ce0 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 9 Oct 2024 15:49:15 -0400 Subject: [PATCH 4/4] use beforeNavigate (#308) * use beforeNavigate * Update apps/svelte.dev/src/routes/+layout.svelte --------- Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com> --- apps/svelte.dev/src/routes/+layout.svelte | 32 +++++++++-------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/apps/svelte.dev/src/routes/+layout.svelte b/apps/svelte.dev/src/routes/+layout.svelte index f0f136d2b6..085d6de94f 100644 --- a/apps/svelte.dev/src/routes/+layout.svelte +++ b/apps/svelte.dev/src/routes/+layout.svelte @@ -6,29 +6,23 @@ import { Nav } from '@sveltejs/site-kit/nav'; import { Search, SearchBox } from '@sveltejs/site-kit/search'; import { injectSpeedInsights } from '@vercel/speed-insights/sveltekit'; - import { afterNavigate } from '$app/navigation'; - import { needs_webcontainers } from './tutorial/[...slug]/shared'; - import type { Exercise } from '$lib/tutorial'; + import { beforeNavigate } from '$app/navigation'; injectSpeedInsights(); - let exercise: Exercise | undefined = undefined; - - afterNavigate(() => { - // Make all navigations between SvelteKit-tutorial and non-SvelteKit-tutorial pages (and vice versa) - // a full page navigation to ensure webcontainers get the correct origin restriction headers while - // ensuring those headers don't interfere with the rest of the page. These headers would have bad - // consequences on how we have to handle integration of images etc from other domains for example. - if ($page.data?.exercise && needs_webcontainers($page.data.exercise)) { - document.body.setAttribute('data-sveltekit-reload', 'true'); - if (!!exercise && !needs_webcontainers(exercise)) { - location.reload(); - } - } else { - document.body.removeAttribute('data-sveltekit-reload'); + // Make all navigations between SvelteKit-tutorial and non-SvelteKit-tutorial pages (and vice versa) + // a full page navigation to ensure webcontainers get the correct origin restriction headers while + // ensuring those headers don't interfere with the rest of the page. These headers would have bad + // consequences on how we have to handle integration of images etc from other domains for example. + beforeNavigate(({ from, to, cancel }) => { + if (!from || !to) return; + + if ( + from.url.pathname.startsWith('/tutorial/kit/') !== to.url.pathname.startsWith('/tutorial/kit') + ) { + cancel(); + location.href = to.url.href; } - - exercise = $page.data?.exercise; }); let { data, children: layout_children } = $props();