diff --git a/packages/server-renderer/__tests__/ssrSuspense.spec.ts b/packages/server-renderer/__tests__/ssrSuspense.spec.ts index eef642d0042..5f8cecaf986 100644 --- a/packages/server-renderer/__tests__/ssrSuspense.spec.ts +++ b/packages/server-renderer/__tests__/ssrSuspense.spec.ts @@ -1,5 +1,7 @@ -import { Suspense, createApp, h } from 'vue' +import { Suspense, createApp, defineComponent, h } from 'vue' import { renderToString } from '../src/renderToString' +import { ssrRenderComponent } from '../src/helpers/ssrRenderComponent' +import { ssrRenderSuspense } from '../src/helpers/ssrRenderSuspense' describe('SSR Suspense', () => { const ResolvingAsync = { @@ -103,6 +105,28 @@ describe('SSR Suspense', () => { expect('missing template').toHaveBeenWarned() }) + // nuxt/nuxt#28162 + test('propagates sync errors from compiled ssrRenderSuspense default slot', async () => { + const Throwing = defineComponent({ + ssrRender(_ctx: any, _push: any) { + throw new TypeError('bang') + }, + }) + + const Root = defineComponent({ + ssrRender(_ctx: any, _push: any, _parent: any) { + ssrRenderSuspense(_push, { + default: () => { + _push(ssrRenderComponent(Throwing, null, null, _parent)) + }, + _: 1, + } as any) + }, + }) + + await expect(renderToString(createApp(Root))).rejects.toThrow('bang') + }) + test('passing suspense in failing suspense', async () => { const Comp = { errorCaptured: vi.fn(() => false), diff --git a/packages/server-renderer/src/helpers/ssrRenderSuspense.ts b/packages/server-renderer/src/helpers/ssrRenderSuspense.ts index 1c6823afa95..1f41d00aa5f 100644 --- a/packages/server-renderer/src/helpers/ssrRenderSuspense.ts +++ b/packages/server-renderer/src/helpers/ssrRenderSuspense.ts @@ -1,9 +1,12 @@ import type { PushFn } from '../render' -export async function ssrRenderSuspense( +// Must remain synchronous: compiled output is `ssrRenderSuspense(_push, ...)`, +// not `_push(ssrRenderSuspense(...))`, so any returned Promise (and its +// rejection) would be silently discarded. +export function ssrRenderSuspense( push: PushFn, { default: renderContent }: Record void) | undefined>, -): Promise { +): void { if (renderContent) { renderContent() } else {