supporting top of await (#6671)
* add fix * fix * revert verison * fix fn is undefined g * add e2e test * fix unit test * delete redundant code * add changeset --------- Co-authored-by: wuls <linsheng.wu@beantechs.com>
This commit is contained in:
parent
07e8a1bab4
commit
d59e511d16
7 changed files with 63 additions and 5 deletions
5
.changeset/spotty-keys-change.md
Normal file
5
.changeset/spotty-keys-change.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@astrojs/vue': patch
|
||||
---
|
||||
|
||||
Supporting the top of the await syntax sugar for Vue in the template's setup
|
|
@ -0,0 +1,19 @@
|
|||
<script setup lang="ts">
|
||||
import {onMounted, ref} from 'vue'
|
||||
const props = defineProps(['id'])
|
||||
/** The top-level await causes event handling to not work (button click) */
|
||||
await new Promise((resolve) => setTimeout(resolve, 10));
|
||||
|
||||
const a = ref(1);
|
||||
|
||||
onMounted(()=>{
|
||||
a.value = 2
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :id="props.id">
|
||||
{{ a }}
|
||||
</div>
|
||||
</template>
|
|
@ -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 = {
|
|||
</Counter>
|
||||
|
||||
<VueComponent id="client-only" client:only="vue" />
|
||||
<AsyncTest id="client-test" client:only="vue" />
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -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 = {
|
|||
</Counter>
|
||||
|
||||
<VueComponent id="client-only" client:only="vue" />
|
||||
|
||||
<AsyncTest id="client-test" client:only="vue" />
|
||||
|
|
|
@ -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');
|
||||
});
|
||||
|
|
|
@ -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';
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue