Skip to content

Commit

Permalink
Fix Svelte view transition state persistence (#12006)
Browse files Browse the repository at this point in the history
Co-authored-by: Martin Trapp <94928215+martrapp@users.noreply.github.com>
  • Loading branch information
johannesspohr and martrapp committed Sep 17, 2024
1 parent daca995 commit a582cb6
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 22 deletions.
5 changes: 5 additions & 0 deletions .changeset/warm-birds-cheer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/svelte': patch
---

Fix Svelte component view transition state persistence
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts">
let count = 0;
export let prefix = "";
function add() {
count += 1;
Expand All @@ -11,9 +12,9 @@
</script>

<div class="counter">
<button on:click={subtract}>-</button>
<pre>{count}</pre>
<button on:click={add}>+</button>
<button on:click={subtract} class="decrement">-</button>
<pre>{prefix}{count}</pre>
<button on:click={add} class="increment">+</button>
</div>
<div class="message">
<slot />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
import Counter from '../components/SvelteCounter.svelte';
import Layout from '../components/Layout.astro';
export const prerender = false;
---
<Layout>
<p id="island-one">Page 1</p>
<a id="click-two" href="/island-svelte-two">go to 2</a>
<Counter prefix="A" client:load transition:persist transition:name="counter"/>
</Layout>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
import Counter from '../components/SvelteCounter.svelte';
import Layout from '../components/Layout.astro';
export const prerender = false;
---
<Layout>
<p id="island-two">Page 2</p>
<a id="click-one" href="/island-svelte-one">go to 1</a>
<Counter prefix="B" client:load transition:persist transition:name="counter"/>
</Layout>
22 changes: 20 additions & 2 deletions packages/astro/e2e/view-transitions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -543,8 +543,8 @@ test.describe('View Transitions', () => {
const pageTitle = page.locator('.page');
await expect(pageTitle).toHaveText('Island 2');
});

test('Solid Islands can persist using transition:persist', async ({ page, astro }) => {
test('Solid Islands can persist using transition:persist', async ({ page, astro }) => {
// Go to page 1
await page.goto(astro.resolveUrl('/island-solid-one'));
let cnt = page.locator('.counter pre');
Expand All @@ -569,6 +569,24 @@ test.describe('View Transitions', () => {
await expect(cnt).toHaveText('A1');
});

test('Svelte Islands can persist using transition:persist', async ({ page, astro }) => {
// Go to page 1
await page.goto(astro.resolveUrl('/island-svelte-one'));
let cnt = page.locator('.counter pre');
await expect(cnt).toHaveText('A0');

await page.click('.increment');
await expect(cnt).toHaveText('A1');

// Navigate to page 2
await page.click('#click-two');
let p = page.locator('#island-two');
await expect(p).toBeVisible();
cnt = page.locator('.counter pre');
// Count should remain, but the prefix should be updated
await expect(cnt).toHaveText('B1');
});

test('Vue Islands can persist using transition:persist', async ({ page, astro }) => {
// Go to page 1
await page.goto(astro.resolveUrl('/island-vue-one'));
Expand Down
22 changes: 16 additions & 6 deletions packages/integrations/svelte/client-v5.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { createRawSnippet, hydrate, mount, unmount } from 'svelte';

const existingApplications = new WeakMap();

export default (element) => {
return async (Component, props, slotted, { client }) => {
if (!element.hasAttribute('ssr')) return;
Expand All @@ -21,15 +23,23 @@ export default (element) => {
}

const bootstrap = client !== 'only' ? hydrate : mount;

const component = bootstrap(Component, {
target: element,
props: {
if (existingApplications.has(element)) {
existingApplications.get(element).$set({
...props,
children,
$$slots,
},
});
});
} else {
const component = bootstrap(Component, {
target: element,
props: {
...props,
children,
$$slots,
},
});
existingApplications.set(element, component);
}

element.addEventListener('astro:unmount', () => unmount(component), { once: true });
};
Expand Down
29 changes: 18 additions & 11 deletions packages/integrations/svelte/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ const noop = () => {};
let originalConsoleWarning;
let consoleFilterRefs = 0;

const existingApplications = new WeakMap();

export default (element) => {
return (Component, props, slotted, { client }) => {
if (!element.hasAttribute('ssr')) return;
Expand All @@ -14,18 +16,23 @@ export default (element) => {
try {
if (import.meta.env.DEV) useConsoleFilter();

const component = new Component({
target: element,
props: {
...props,
$$slots: slots,
$$scope: { ctx: [] },
},
hydrate: client !== 'only',
$$inline: true,
});
if (existingApplications.has(element)) {
existingApplications.get(element).$set({ ...props, $$slots: slots, $$scope: { ctx: [] } });
} else {
const component = new Component({
target: element,
props: {
...props,
$$slots: slots,
$$scope: { ctx: [] },
},
hydrate: client !== 'only',
$$inline: true,
});
existingApplications.set(element, component);

element.addEventListener('astro:unmount', () => component.$destroy(), { once: true });
element.addEventListener('astro:unmount', () => component.$destroy(), { once: true });
}
} finally {
if (import.meta.env.DEV) finishUsingConsoleFilter();
}
Expand Down

0 comments on commit a582cb6

Please sign in to comment.