Skip to content

Commit

Permalink
fix(ssr): ensure async setup error handling work with suspense during…
Browse files Browse the repository at this point in the history
… ssr
  • Loading branch information
yyx990803 committed Mar 26, 2021
1 parent d668d48 commit 2e71f07
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 29 deletions.
14 changes: 9 additions & 5 deletions packages/runtime-core/src/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
} from './componentProps'
import { Slots, initSlots, InternalSlots } from './componentSlots'
import { warn } from './warning'
import { ErrorCodes, callWithAsyncErrorHandling } from './errorHandling'
import { ErrorCodes, callWithErrorHandling, handleError } from './errorHandling'
import { AppContext, createAppContext, AppConfig } from './apiCreateApp'
import { Directive, validateDirectiveName } from './directives'
import {
Expand Down Expand Up @@ -579,7 +579,7 @@ function setupStatefulComponent(

currentInstance = instance
pauseTracking()
const setupResult = callWithAsyncErrorHandling(
const setupResult = callWithErrorHandling(
setup,
instance,
ErrorCodes.SETUP_FUNCTION,
Expand All @@ -591,9 +591,13 @@ function setupStatefulComponent(
if (isPromise(setupResult)) {
if (isSSR) {
// return the promise so server-renderer can wait on it
return setupResult.then((resolvedResult: unknown) => {
handleSetupResult(instance, resolvedResult, isSSR)
})
return setupResult
.then((resolvedResult: unknown) => {
handleSetupResult(instance, resolvedResult, isSSR)
})
.catch(e => {
handleError(e, instance, ErrorCodes.SETUP_FUNCTION)
})
} else if (__FEATURE_SUSPENSE__) {
// async setup returned Promise.
// bail here and wait for re-entry.
Expand Down
4 changes: 1 addition & 3 deletions packages/server-renderer/__tests__/render.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -811,10 +811,8 @@ function testRender(type: string, render: typeof renderToString) {

expect(fn2).toHaveBeenCalledTimes(1)
expect(fn2).toBeCalledWith('async child error')

expect('Uncaught error in async setup').toHaveBeenWarned()
})

// https://github.com/vuejs/vue-next/issues/3322
test('effect onInvalidate does not error', async () => {
const noop = () => {}
Expand Down
27 changes: 11 additions & 16 deletions packages/server-renderer/__tests__/ssrSuspense.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ describe('SSR Suspense', () => {

test('reject', async () => {
const Comp = {
errorCaptured: jest.fn(() => false),
render() {
return h(Suspense, null, {
default: h(RejectingAsync),
Expand All @@ -38,10 +39,8 @@ 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(Comp.errorCaptured).toHaveBeenCalledTimes(1)
expect('missing template').toHaveBeenWarned()
})

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

test('resolving component + rejecting component', async () => {
const Comp = {
errorCaptured: jest.fn(() => false),
render() {
return h(Suspense, null, {
default: h('div', [h(ResolvingAsync), h(RejectingAsync)]),
Expand All @@ -73,15 +73,14 @@ describe('SSR Suspense', () => {
expect(await renderToString(createApp(Comp))).toBe(
`<div><div>async</div><!----></div>`
)
expect('Uncaught error in async setup').toHaveBeenWarned()
expect(
'Unhandled error during execution of setup function'
).toHaveBeenWarned()

expect(Comp.errorCaptured).toHaveBeenCalledTimes(1)
expect('missing template or render function').toHaveBeenWarned()
})

test('failing suspense in passing suspense', async () => {
const Comp = {
errorCaptured: jest.fn(() => false),
render() {
return h(Suspense, null, {
default: h('div', [
Expand All @@ -99,15 +98,14 @@ describe('SSR Suspense', () => {
expect(await renderToString(createApp(Comp))).toBe(
`<div><div>async</div><div><!----></div></div>`
)
expect('Uncaught error in async setup').toHaveBeenWarned()
expect(
'Unhandled error during execution of setup function'
).toHaveBeenWarned()

expect(Comp.errorCaptured).toHaveBeenCalledTimes(1)
expect('missing template').toHaveBeenWarned()
})

test('passing suspense in failing suspense', async () => {
const Comp = {
errorCaptured: jest.fn(() => false),
render() {
return h(Suspense, null, {
default: h('div', [
Expand All @@ -125,10 +123,7 @@ describe('SSR Suspense', () => {
expect(await renderToString(createApp(Comp))).toBe(
`<div><!----><div><div>async</div></div></div>`
)
expect('Uncaught error in async setup').toHaveBeenWarned()
expect(
'Unhandled error during execution of setup function'
).toHaveBeenWarned()
expect(Comp.errorCaptured).toHaveBeenCalledTimes(1)
expect('missing template').toHaveBeenWarned()
})
})
6 changes: 1 addition & 5 deletions packages/server-renderer/src/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,7 @@ export function renderComponentVNode(
const hasAsyncSetup = isPromise(res)
const prefetch = (vnode.type as ComponentOptions).serverPrefetch
if (hasAsyncSetup || prefetch) {
let p = hasAsyncSetup
? (res as Promise<void>).catch(err => {
warn(`[@vue/server-renderer]: Uncaught error in async setup:\n`, err)
})
: Promise.resolve()
let p = hasAsyncSetup ? (res as Promise<void>) : Promise.resolve()
if (prefetch) {
p = p.then(() => prefetch.call(instance.proxy)).catch(err => {
warn(`[@vue/server-renderer]: Uncaught error in serverPrefetch:\n`, err)
Expand Down

0 comments on commit 2e71f07

Please sign in to comment.