diff --git a/.changeset/spotty-keys-change.md b/.changeset/spotty-keys-change.md new file mode 100644 index 000000000000..3518721f3267 --- /dev/null +++ b/.changeset/spotty-keys-change.md @@ -0,0 +1,5 @@ +--- +'@astrojs/vue': patch +--- + +Supporting the top of the await syntax sugar for Vue in the template's setup diff --git a/packages/astro/e2e/fixtures/vue-component/src/components/Test.vue b/packages/astro/e2e/fixtures/vue-component/src/components/Test.vue new file mode 100644 index 000000000000..da05a10295f4 --- /dev/null +++ b/packages/astro/e2e/fixtures/vue-component/src/components/Test.vue @@ -0,0 +1,19 @@ + + + diff --git a/packages/astro/e2e/fixtures/vue-component/src/pages/index.astro b/packages/astro/e2e/fixtures/vue-component/src/pages/index.astro index 73b5b2cf06f4..5ea9823b6376 100644 --- a/packages/astro/e2e/fixtures/vue-component/src/pages/index.astro +++ b/packages/astro/e2e/fixtures/vue-component/src/pages/index.astro @@ -1,6 +1,7 @@ --- import Counter from '../components/Counter.vue'; import VueComponent from '../components/VueComponent.vue'; +import AsyncTest from '../components/Test.vue' const someProps = { count: 0, @@ -33,5 +34,6 @@ const someProps = { + diff --git a/packages/astro/e2e/fixtures/vue-component/src/pages/mdx.mdx b/packages/astro/e2e/fixtures/vue-component/src/pages/mdx.mdx index 5d0a141b0f27..ed8d80746c5b 100644 --- a/packages/astro/e2e/fixtures/vue-component/src/pages/mdx.mdx +++ b/packages/astro/e2e/fixtures/vue-component/src/pages/mdx.mdx @@ -1,6 +1,7 @@ export { default } from '../components/Layout.astro'; import Counter from '../components/Counter.vue'; import VueComponent from '../components/VueComponent.vue'; +import AsyncTest from '../components/Test.vue'; export const someProps = { count: 0, @@ -27,3 +28,5 @@ export const someProps = { + + diff --git a/packages/astro/e2e/vue-component.test.js b/packages/astro/e2e/vue-component.test.js index 0cc41c74eb2b..42f0d80ef1f2 100644 --- a/packages/astro/e2e/vue-component.test.js +++ b/packages/astro/e2e/vue-component.test.js @@ -1,5 +1,5 @@ import { prepareTestFactory } from './shared-component-tests.js'; - +import { expect } from '@playwright/test'; const { test, createTests } = prepareTestFactory({ root: './fixtures/vue-component/' }); const config = { @@ -23,3 +23,20 @@ test.describe('Vue components in MDX files', () => { pageSourceFilePath: './src/pages/mdx.mdx', }); }); + + +test('test the async vue component in astro', async ({ page, astro }) => { + await page.goto(astro.resolveUrl('/')); + + const label = page.locator('#client-test'); + + await expect(label, 'component not hydrated').toHaveText('2'); +}); + +test('test the async vue component in mdx', async ({ page, astro }) => { + await page.goto(astro.resolveUrl('/mdx/')); + + const label = page.locator('#client-test'); + + await expect(label, 'component not hydrated').toHaveText('2'); +}); diff --git a/packages/integrations/vue/client.js b/packages/integrations/vue/client.js index 7e67825df302..508cc59c0c8c 100644 --- a/packages/integrations/vue/client.js +++ b/packages/integrations/vue/client.js @@ -1,4 +1,4 @@ -import { h, createSSRApp, createApp } from 'vue'; +import { h, createSSRApp, createApp, Suspense } from 'vue'; import { setup } from 'virtual:@astrojs/vue/app'; import StaticHtml from './static-html.js'; @@ -13,13 +13,26 @@ export default (element) => for (const [key, value] of Object.entries(slotted)) { slots[key] = () => h(StaticHtml, { value, name: key === 'default' ? undefined : key }); } + + 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) + } + if (client === 'only') { - const app = createApp({ name, render: () => h(Component, props, slots) }); + const app = createApp({ name, render: () => content }); await setup(app); app.mount(element, false); } else { - const app = createSSRApp({ name, render: () => h(Component, props, slots) }); + const app = createSSRApp({ name, render: () => content }); await setup(app); app.mount(element, true); } }; + +function isAsync (fn) { + const constructor = fn?.constructor + return constructor && constructor.name === 'AsyncFunction'; +} diff --git a/packages/integrations/vue/test/app-entrypoint.test.js b/packages/integrations/vue/test/app-entrypoint.test.js index 0c60818a312d..5c9ea840c382 100644 --- a/packages/integrations/vue/test/app-entrypoint.test.js +++ b/packages/integrations/vue/test/app-entrypoint.test.js @@ -1,7 +1,6 @@ import { loadFixture } from './test-utils.js'; import { expect } from 'chai'; import { parseHTML } from 'linkedom'; - describe('App Entrypoint', () => { /** @type {import('./test-utils').Fixture} */ let fixture;