Skip to content

Commit

Permalink
Merge branch 'main' into fix-solidjs-view-transition-persistence
Browse files Browse the repository at this point in the history
  • Loading branch information
martrapp authored Sep 17, 2024
2 parents 95a8ff3 + b75bfc8 commit bcea4ad
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 20 deletions.
5 changes: 5 additions & 0 deletions .changeset/five-walls-build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/vue': patch
---

Fix vue islands keeping their state when using view transition persistence
5 changes: 5 additions & 0 deletions .changeset/healthy-donuts-yell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fixes an outdated link used to document Content Layer API
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<template>
<div class="counter">
<button @click="subtract()">-</button>
<pre>{{ count }}</pre>
<button @click="add()">+</button>
<button @click="subtract()" class="decrement">-</button>
<pre>{{prefix}}{{ count }}</pre>
<button @click="add()" class="increment">+</button>
</div>
<div class="counter-message">
<slot />
Expand All @@ -12,6 +12,12 @@
<script lang="ts">
import { ref } from 'vue';
export default {
props: {
prefix: {
type: String,
default: '',
},
},
setup() {
const count = ref(0);
const add = () => (count.value = count.value + 1);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
import Layout from '../components/Layout.astro';
import Counter from '../components/VueCounter.vue';
export const prerender = false;
---
<Layout>
<p id="island-one">Page 1</p>
<a id="click-two" href="/island-vue-two">go to 2</a>
<Counter prefix="AA" client:load transition:persist transition:name="counter" />
</Layout>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
import Layout from '../components/Layout.astro';
import Counter from '../components/VueCounter.vue';
export const prerender = false;
---
<Layout>
<p id="island-two">Page 2</p>
<a id="click-two" href="/island-vue-one">go to 1</a>
<Counter prefix="BB" client:load transition:persist transition:name="counter" />
</Layout>
20 changes: 19 additions & 1 deletion packages/astro/e2e/view-transitions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,7 @@ test.describe('View Transitions', () => {
expect(secondTime).toBeGreaterThanOrEqual(firstTime);
});

test('Islands can persist using transition:persist', async ({ page, astro }) => {
test('React Islands can persist using transition:persist', async ({ page, astro }) => {
// Go to page 1
await page.goto(astro.resolveUrl('/island-one'));
let cnt = page.locator('.counter pre');
Expand Down Expand Up @@ -567,6 +567,24 @@ test.describe('View Transitions', () => {
cnt = page.locator('.counter pre');
// Count should remain, but the postfix should be removed again (to test unsetting props)
await expect(cnt).toHaveText('A1');
});

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

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

// Navigate to page 2
await page.click('#click-two');
const 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('BB1');
});

test('transition:persist-props prevents props from changing', async ({ page, astro }) => {
Expand Down
4 changes: 2 additions & 2 deletions packages/astro/src/@types/astro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2279,7 +2279,7 @@ export interface AstroUserConfig {
* export const collections = { countries };
* ```
*
* For more advanced loading logic, you can define an object loader. This allows incremental updates and conditional loading while also giving full access to the data store. See the API in [the Content Layer API RFC](https://github.com/withastro/roadmap/blob/content-layer/proposals/0047-content-layer.md#loaders).
* For more advanced loading logic, you can define an object loader. This allows incremental updates and conditional loading while also giving full access to the data store. See the API in [the Content Layer API RFC](https://github.com/withastro/roadmap/blob/content-layer/proposals/0050-content-layer.md#loaders).
*
* #### Migrating an existing content collection to use the Content Layer API
*
Expand Down Expand Up @@ -2344,7 +2344,7 @@ export interface AstroUserConfig {
*
* #### Learn more
*
* For a complete overview and the full API reference, see [the Content Layer API RFC](https://github.com/withastro/roadmap/blob/content-layer/proposals/0047-content-layer.md) and [share your feedback](https://github.com/withastro/roadmap/pull/982).
* For a complete overview and the full API reference, see [the Content Layer API RFC](https://github.com/withastro/roadmap/blob/content-layer/proposals/0050-content-layer.md) and [share your feedback](https://github.com/withastro/roadmap/pull/982).
*/
contentLayer?: boolean;
};
Expand Down
46 changes: 32 additions & 14 deletions packages/integrations/vue/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { setup } from 'virtual:@astrojs/vue/app';
import { Suspense, createApp, createSSRApp, h } from 'vue';
import StaticHtml from './static-html.js';

// keep track of already initialized apps, so we don't hydrate again for view transitions
let appMap = new WeakMap();

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

const isHydrate = client !== 'only';
const bootstrap = isHydrate ? createSSRApp : createApp;
const app = bootstrap({
name,
render() {
let content = h(Component, props, slots);
// related to https://github.com/withastro/astro/issues/6549
// if the component is async, wrap it in a Suspense component
if (isAsync(Component.setup)) {
content = h(Suspense, null, content);
}
return content;
},
});
await setup(app);
app.mount(element, isHydrate);

// keep a reference to the app, props and slots so we can update a running instance later
let appInstance = appMap.get(element);

if (!appInstance) {
appInstance = {
props,
slots,
};
const app = bootstrap({
name,
render() {
let content = h(Component, appInstance.props, appInstance.slots);
appInstance.component = this;
// related to https://github.com/withastro/astro/issues/6549
// if the component is async, wrap it in a Suspense component
if (isAsync(Component.setup)) {
content = h(Suspense, null, content);
}
return content;
},
});
await setup(app);
app.mount(element, isHydrate);
appMap.set(element, appInstance);
} else {
appInstance.props = props;
appInstance.slots = slots;
appInstance.component.$forceUpdate();
}
element.addEventListener('astro:unmount', () => app.unmount(), { once: true });
};

Expand Down

0 comments on commit bcea4ad

Please sign in to comment.