diff --git a/packages/nuxt/src/app/components/client-fallback.server.ts b/packages/nuxt/src/app/components/client-fallback.server.ts index f4229867c9..3b07745b38 100644 --- a/packages/nuxt/src/app/components/client-fallback.server.ts +++ b/packages/nuxt/src/app/components/client-fallback.server.ts @@ -1,6 +1,9 @@ import { defineComponent, getCurrentInstance, onErrorCaptured, ref } from 'vue' import { ssrRenderAttrs, ssrRenderSlot, ssrRenderVNode } from 'vue/server-renderer' +// eslint-disable-next-line +import { isPromise } from '@vue/shared' import { useState } from '../composables/state' +import { useNuxtApp } from '../nuxt' import { createBuffer } from './utils' const NuxtClientFallbackServer = defineComponent({ @@ -34,9 +37,10 @@ const NuxtClientFallbackServer = defineComponent({ return true } }, - setup (props, ctx) { + async setup (props, ctx) { const vm = getCurrentInstance() const ssrFailed = ref(false) + const nuxtApp = useNuxtApp() onErrorCaptured((err) => { useState(`${props.uid}`, () => true) @@ -53,10 +57,15 @@ const NuxtClientFallbackServer = defineComponent({ ssrRenderVNode(ssrVNodes.push, defaultSlot![i], vm!) } + const buffer = ssrVNodes.getBuffer() + if (buffer.hasAsync) { + await Promise.all(buffer.filter(isPromise)) + } + return { ssrFailed, ssrVNodes } } catch (ssrError) { // catch in dev - useState(`${props.uid}`, () => true) + nuxtApp.runWithContext(() => useState(`${props.uid}`, () => true)) ctx.emit('ssr-error', ssrError) return { ssrFailed: true, ssrVNodes: [] } } diff --git a/test/basic.test.ts b/test/basic.test.ts index 4e5d42b3d6..10455df657 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -424,7 +424,8 @@ describe('pages', () => { 'clientfallback-non-stateful-setup', 'clientfallback-non-stateful', 'clientfallback-stateful-setup', - 'clientfallback-stateful' + 'clientfallback-stateful', + 'clientfallback-async-setup' ] const html = await $fetch('/client-fallback') // ensure failed components are not rendered server-side @@ -441,6 +442,9 @@ describe('pages', () => { expect(html).not.toContain('
') expect(html).toContain('hi') + // aysnc setup + expect(html).toContain('Work with async setup') + const { page, pageErrors } = await renderPage('/client-fallback') // ensure components reactivity once mounted await page.locator('#increment-count').click() diff --git a/test/fixtures/basic/components/BreakInAsyncSetup.vue b/test/fixtures/basic/components/BreakInAsyncSetup.vue new file mode 100644 index 0000000000..8212300848 --- /dev/null +++ b/test/fixtures/basic/components/BreakInAsyncSetup.vue @@ -0,0 +1,14 @@ + + + +