Skip to content

Commit 2e71f07

Browse files
committed
fix(ssr): ensure async setup error handling work with suspense during ssr
1 parent d668d48 commit 2e71f07

File tree

4 files changed

+22
-29
lines changed

4 files changed

+22
-29
lines changed

packages/runtime-core/src/component.ts

+9-5
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
} from './componentProps'
2424
import { Slots, initSlots, InternalSlots } from './componentSlots'
2525
import { warn } from './warning'
26-
import { ErrorCodes, callWithAsyncErrorHandling } from './errorHandling'
26+
import { ErrorCodes, callWithErrorHandling, handleError } from './errorHandling'
2727
import { AppContext, createAppContext, AppConfig } from './apiCreateApp'
2828
import { Directive, validateDirectiveName } from './directives'
2929
import {
@@ -579,7 +579,7 @@ function setupStatefulComponent(
579579

580580
currentInstance = instance
581581
pauseTracking()
582-
const setupResult = callWithAsyncErrorHandling(
582+
const setupResult = callWithErrorHandling(
583583
setup,
584584
instance,
585585
ErrorCodes.SETUP_FUNCTION,
@@ -591,9 +591,13 @@ function setupStatefulComponent(
591591
if (isPromise(setupResult)) {
592592
if (isSSR) {
593593
// return the promise so server-renderer can wait on it
594-
return setupResult.then((resolvedResult: unknown) => {
595-
handleSetupResult(instance, resolvedResult, isSSR)
596-
})
594+
return setupResult
595+
.then((resolvedResult: unknown) => {
596+
handleSetupResult(instance, resolvedResult, isSSR)
597+
})
598+
.catch(e => {
599+
handleError(e, instance, ErrorCodes.SETUP_FUNCTION)
600+
})
597601
} else if (__FEATURE_SUSPENSE__) {
598602
// async setup returned Promise.
599603
// bail here and wait for re-entry.

packages/server-renderer/__tests__/render.spec.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -811,10 +811,8 @@ function testRender(type: string, render: typeof renderToString) {
811811

812812
expect(fn2).toHaveBeenCalledTimes(1)
813813
expect(fn2).toBeCalledWith('async child error')
814-
815-
expect('Uncaught error in async setup').toHaveBeenWarned()
816814
})
817-
815+
818816
// https://github.com/vuejs/vue-next/issues/3322
819817
test('effect onInvalidate does not error', async () => {
820818
const noop = () => {}

packages/server-renderer/__tests__/ssrSuspense.spec.ts

+11-16
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ describe('SSR Suspense', () => {
2929

3030
test('reject', async () => {
3131
const Comp = {
32+
errorCaptured: jest.fn(() => false),
3233
render() {
3334
return h(Suspense, null, {
3435
default: h(RejectingAsync),
@@ -38,10 +39,8 @@ describe('SSR Suspense', () => {
3839
}
3940

4041
expect(await renderToString(createApp(Comp))).toBe(`<!---->`)
41-
expect('Uncaught error in async setup').toHaveBeenWarned()
42-
expect(
43-
'Unhandled error during execution of setup function'
44-
).toHaveBeenWarned()
42+
43+
expect(Comp.errorCaptured).toHaveBeenCalledTimes(1)
4544
expect('missing template').toHaveBeenWarned()
4645
})
4746

@@ -62,6 +61,7 @@ describe('SSR Suspense', () => {
6261

6362
test('resolving component + rejecting component', async () => {
6463
const Comp = {
64+
errorCaptured: jest.fn(() => false),
6565
render() {
6666
return h(Suspense, null, {
6767
default: h('div', [h(ResolvingAsync), h(RejectingAsync)]),
@@ -73,15 +73,14 @@ describe('SSR Suspense', () => {
7373
expect(await renderToString(createApp(Comp))).toBe(
7474
`<div><div>async</div><!----></div>`
7575
)
76-
expect('Uncaught error in async setup').toHaveBeenWarned()
77-
expect(
78-
'Unhandled error during execution of setup function'
79-
).toHaveBeenWarned()
76+
77+
expect(Comp.errorCaptured).toHaveBeenCalledTimes(1)
8078
expect('missing template or render function').toHaveBeenWarned()
8179
})
8280

8381
test('failing suspense in passing suspense', async () => {
8482
const Comp = {
83+
errorCaptured: jest.fn(() => false),
8584
render() {
8685
return h(Suspense, null, {
8786
default: h('div', [
@@ -99,15 +98,14 @@ describe('SSR Suspense', () => {
9998
expect(await renderToString(createApp(Comp))).toBe(
10099
`<div><div>async</div><div><!----></div></div>`
101100
)
102-
expect('Uncaught error in async setup').toHaveBeenWarned()
103-
expect(
104-
'Unhandled error during execution of setup function'
105-
).toHaveBeenWarned()
101+
102+
expect(Comp.errorCaptured).toHaveBeenCalledTimes(1)
106103
expect('missing template').toHaveBeenWarned()
107104
})
108105

109106
test('passing suspense in failing suspense', async () => {
110107
const Comp = {
108+
errorCaptured: jest.fn(() => false),
111109
render() {
112110
return h(Suspense, null, {
113111
default: h('div', [
@@ -125,10 +123,7 @@ describe('SSR Suspense', () => {
125123
expect(await renderToString(createApp(Comp))).toBe(
126124
`<div><!----><div><div>async</div></div></div>`
127125
)
128-
expect('Uncaught error in async setup').toHaveBeenWarned()
129-
expect(
130-
'Unhandled error during execution of setup function'
131-
).toHaveBeenWarned()
126+
expect(Comp.errorCaptured).toHaveBeenCalledTimes(1)
132127
expect('missing template').toHaveBeenWarned()
133128
})
134129
})

packages/server-renderer/src/render.ts

+1-5
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,7 @@ export function renderComponentVNode(
8989
const hasAsyncSetup = isPromise(res)
9090
const prefetch = (vnode.type as ComponentOptions).serverPrefetch
9191
if (hasAsyncSetup || prefetch) {
92-
let p = hasAsyncSetup
93-
? (res as Promise<void>).catch(err => {
94-
warn(`[@vue/server-renderer]: Uncaught error in async setup:\n`, err)
95-
})
96-
: Promise.resolve()
92+
let p = hasAsyncSetup ? (res as Promise<void>) : Promise.resolve()
9793
if (prefetch) {
9894
p = p.then(() => prefetch.call(instance.proxy)).catch(err => {
9995
warn(`[@vue/server-renderer]: Uncaught error in serverPrefetch:\n`, err)

0 commit comments

Comments
 (0)