From e5d8b9cbd4378ab4ce6ad76620e7abffe26f1453 Mon Sep 17 00:00:00 2001 From: daiwei Date: Fri, 25 Dec 2020 14:28:23 +0800 Subject: [PATCH 1/3] fix(server-render): caught error in async setup and serverPrefetch --- packages/runtime-core/src/component.ts | 4 ++-- packages/server-renderer/src/render.ts | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 9b142036219..63aed8fc52a 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -23,7 +23,7 @@ import { } from './componentProps' import { Slots, initSlots, InternalSlots } from './componentSlots' import { warn } from './warning' -import { ErrorCodes, callWithErrorHandling } from './errorHandling' +import { ErrorCodes, callWithAsyncErrorHandling } from './errorHandling' import { AppContext, createAppContext, AppConfig } from './apiCreateApp' import { Directive, validateDirectiveName } from './directives' import { @@ -573,7 +573,7 @@ function setupStatefulComponent( currentInstance = instance pauseTracking() - const setupResult = callWithErrorHandling( + const setupResult = callWithAsyncErrorHandling( setup, instance, ErrorCodes.SETUP_FUNCTION, diff --git a/packages/server-renderer/src/render.ts b/packages/server-renderer/src/render.ts index 938a4f83a4f..47a50ccd4c1 100644 --- a/packages/server-renderer/src/render.ts +++ b/packages/server-renderer/src/render.ts @@ -90,11 +90,13 @@ export function renderComponentVNode( let p = hasAsyncSetup ? (res as Promise).catch(err => { warn(`[@vue/server-renderer]: Uncaught error in async setup:\n`, err) + throw new Error(err) }) : Promise.resolve() if (prefetch) { p = p.then(() => prefetch.call(instance.proxy)).catch(err => { warn(`[@vue/server-renderer]: Uncaught error in serverPrefetch:\n`, err) + throw new Error(err) }) } return p.then(() => renderComponentSubTree(instance)) From 8a431f8bc0f9a463cd9a7a9b2f08d71fa28baa0c Mon Sep 17 00:00:00 2001 From: daiwei Date: Fri, 25 Dec 2020 15:25:30 +0800 Subject: [PATCH 2/3] fix(server-render): caught error in async setup and serverPrefetch --- .../server-renderer/__tests__/ssrSuspense.spec.ts | 12 ++++++++++++ packages/server-renderer/src/render.ts | 2 -- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/server-renderer/__tests__/ssrSuspense.spec.ts b/packages/server-renderer/__tests__/ssrSuspense.spec.ts index a7d10787833..3cdd8137370 100644 --- a/packages/server-renderer/__tests__/ssrSuspense.spec.ts +++ b/packages/server-renderer/__tests__/ssrSuspense.spec.ts @@ -39,6 +39,9 @@ describe('SSR Suspense', () => { expect(await renderToString(createApp(Comp))).toBe(``) expect('Uncaught error in async setup').toHaveBeenWarned() + expect( + 'Unhandled error during execution of setup function' + ).toHaveBeenWarned() expect('missing template').toHaveBeenWarned() }) @@ -71,6 +74,9 @@ describe('SSR Suspense', () => { `
async
` ) expect('Uncaught error in async setup').toHaveBeenWarned() + expect( + 'Unhandled error during execution of setup function' + ).toHaveBeenWarned() expect('missing template or render function').toHaveBeenWarned() }) @@ -94,6 +100,9 @@ describe('SSR Suspense', () => { `
async
` ) expect('Uncaught error in async setup').toHaveBeenWarned() + expect( + 'Unhandled error during execution of setup function' + ).toHaveBeenWarned() expect('missing template').toHaveBeenWarned() }) @@ -117,6 +126,9 @@ describe('SSR Suspense', () => { `
async
` ) expect('Uncaught error in async setup').toHaveBeenWarned() + expect( + 'Unhandled error during execution of setup function' + ).toHaveBeenWarned() expect('missing template').toHaveBeenWarned() }) }) diff --git a/packages/server-renderer/src/render.ts b/packages/server-renderer/src/render.ts index 47a50ccd4c1..938a4f83a4f 100644 --- a/packages/server-renderer/src/render.ts +++ b/packages/server-renderer/src/render.ts @@ -90,13 +90,11 @@ export function renderComponentVNode( let p = hasAsyncSetup ? (res as Promise).catch(err => { warn(`[@vue/server-renderer]: Uncaught error in async setup:\n`, err) - throw new Error(err) }) : Promise.resolve() if (prefetch) { p = p.then(() => prefetch.call(instance.proxy)).catch(err => { warn(`[@vue/server-renderer]: Uncaught error in serverPrefetch:\n`, err) - throw new Error(err) }) } return p.then(() => renderComponentSubTree(instance)) From 14d52e25149e4360278901d5e0965a69047b43b6 Mon Sep 17 00:00:00 2001 From: daiwei Date: Fri, 5 Mar 2021 14:30:05 +0800 Subject: [PATCH 3/3] fix(server-render): handling error in async setup --- .../server-renderer/__tests__/render.spec.ts | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/packages/server-renderer/__tests__/render.spec.ts b/packages/server-renderer/__tests__/render.spec.ts index a02bf365cb7..6e5d5702031 100644 --- a/packages/server-renderer/__tests__/render.spec.ts +++ b/packages/server-renderer/__tests__/render.spec.ts @@ -715,5 +715,43 @@ function testRender(type: string, render: typeof renderToString) { const html = await render(app) expect(html).toBe(`
hello
`) }) + + // #2763 + test('error handling w/ async setup', async () => { + const fn = jest.fn() + const fn2 = jest.fn() + + const asyncChildren = defineComponent({ + async setup() { + return Promise.reject('async child error') + }, + template: `
asyncChildren
` + }) + const app = createApp({ + name: 'App', + components: { + asyncChildren + }, + template: `
`, + errorCaptured(error) { + fn(error) + } + }) + + app.config.errorHandler = error => { + fn2(error) + } + + const html = await renderToString(app) + expect(html).toBe(`
asyncChildren
`) + + expect(fn).toHaveBeenCalledTimes(1) + expect(fn).toBeCalledWith('async child error') + + expect(fn2).toHaveBeenCalledTimes(1) + expect(fn2).toBeCalledWith('async child error') + + expect('Uncaught error in async setup').toHaveBeenWarned() + }) }) }