fix(nuxt): treat client useAsyncData calls as async boundaries (#30343)

This commit is contained in:
Julien Huang 2024-12-24 15:25:09 +01:00 committed by GitHub
parent 5f046a779d
commit 0f8740636d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 29 additions and 0 deletions

View File

@ -350,6 +350,12 @@ export function useAsyncData<
if (import.meta.client) { if (import.meta.client) {
// Setup hook callbacks once per instance // Setup hook callbacks once per instance
const instance = getCurrentInstance() const instance = getCurrentInstance()
// @ts-expect-error - instance.sp is an internal vue property
if (instance && fetchOnServer && options.immediate && !instance.sp) {
// @ts-expect-error - internal vue property. This force vue to mark the component as async boundary client-side to avoid useId hydration issue since we treeshake onServerPrefetch
instance.sp = []
}
if (import.meta.dev && !nuxtApp.isHydrating && !nuxtApp._processingMiddleware /* internal flag */ && (!instance || instance?.isMounted)) { if (import.meta.dev && !nuxtApp.isHydrating && !nuxtApp._processingMiddleware /* internal flag */ && (!instance || instance?.isMounted)) {
// @ts-expect-error private property // @ts-expect-error private property
console.warn(`[nuxt] [${options._functionName || 'useAsyncData'}] Component is already mounted, please use $fetch instead. See https://nuxt.com/docs/getting-started/data-fetching`) console.warn(`[nuxt] [${options._functionName || 'useAsyncData'}] Component is already mounted, please use $fetch instead. See https://nuxt.com/docs/getting-started/data-fetching`)

View File

@ -2625,6 +2625,11 @@ describe.skipIf(isWindows)('useAsyncData', () => {
await page.close() await page.close()
}) })
it('works with useId', async () => {
const html = await $fetch<string>('/useAsyncData/use-id')
expect(html).toContain('<div>v-0-0-0</div> v-0-0</div>')
await expectNoClientErrors('/useAsyncData/use-id')
})
}) })
describe.runIf(isDev())('component testing', () => { describe.runIf(isDev())('component testing', () => {

View File

@ -0,0 +1,18 @@
<script setup lang="ts">
const Child = defineComponent({
setup () {
const id = useId()
return () => h('div', id)
},
})
const id = useId()
useAsyncData('test', () => Promise.resolve('A'))
</script>
<template>
<div>
<Child />
{{ id }}
</div>
</template>