@@ -10,7 +10,6 @@ import {
10
10
Fragment ,
11
11
ssrUtils ,
12
12
Slots ,
13
- warn ,
14
13
createApp ,
15
14
ssrContextKey
16
15
} from 'vue'
@@ -139,6 +138,8 @@ export function renderComponent(
139
138
)
140
139
}
141
140
141
+ export const AsyncSetupErrorMarker = Symbol ( 'Vue async setup error' )
142
+
142
143
function renderComponentVNode (
143
144
vnode : VNode ,
144
145
parentComponent : ComponentInternalInstance | null = null
@@ -150,7 +151,21 @@ function renderComponentVNode(
150
151
true /* isSSR */
151
152
)
152
153
if ( isPromise ( res ) ) {
153
- return res . then ( ( ) => renderComponentSubTree ( instance ) )
154
+ return res
155
+ . catch ( err => {
156
+ // normalize async setup rejection
157
+ if ( ! ( err instanceof Error ) ) {
158
+ err = new Error ( String ( err ) )
159
+ }
160
+ err [ AsyncSetupErrorMarker ] = true
161
+ console . error (
162
+ `[@vue/server-renderer]: Uncaught error in async setup:\n` ,
163
+ err
164
+ )
165
+ // rethrow for suspense
166
+ throw err
167
+ } )
168
+ . then ( ( ) => renderComponentSubTree ( instance ) )
154
169
} else {
155
170
return renderComponentSubTree ( instance )
156
171
}
@@ -208,15 +223,17 @@ function ssrCompile(
208
223
isNativeTag : instance . appContext . config . isNativeTag || NO ,
209
224
onError ( err : CompilerError ) {
210
225
if ( __DEV__ ) {
211
- const message = `Template compilation error: ${ err . message } `
226
+ const message = `[@vue/server-renderer] Template compilation error: ${
227
+ err . message
228
+ } `
212
229
const codeFrame =
213
230
err . loc &&
214
231
generateCodeFrame (
215
232
template as string ,
216
233
err . loc . start . offset ,
217
234
err . loc . end . offset
218
235
)
219
- warn ( codeFrame ? `${ message } \n${ codeFrame } ` : message )
236
+ console . error ( codeFrame ? `${ message } \n${ codeFrame } ` : message )
220
237
} else {
221
238
throw err
222
239
}
@@ -243,15 +260,15 @@ function renderVNode(
243
260
break
244
261
default :
245
262
if ( shapeFlag & ShapeFlags . ELEMENT ) {
246
- renderElement ( push , vnode , parentComponent )
263
+ renderElementVNode ( push , vnode , parentComponent )
247
264
} else if ( shapeFlag & ShapeFlags . COMPONENT ) {
248
265
push ( renderComponentVNode ( vnode , parentComponent ) )
249
266
} else if ( shapeFlag & ShapeFlags . PORTAL ) {
250
- renderPortal ( vnode , parentComponent )
267
+ renderPortalVNode ( vnode , parentComponent )
251
268
} else if ( shapeFlag & ShapeFlags . SUSPENSE ) {
252
- push ( renderSuspense ( vnode , parentComponent ) )
269
+ push ( renderSuspenseVNode ( vnode , parentComponent ) )
253
270
} else {
254
- console . warn (
271
+ console . error (
255
272
'[@vue/server-renderer] Invalid VNode type:' ,
256
273
type ,
257
274
`(${ typeof type } )`
@@ -270,7 +287,7 @@ export function renderVNodeChildren(
270
287
}
271
288
}
272
289
273
- function renderElement (
290
+ function renderElementVNode (
274
291
push : PushFn ,
275
292
vnode : VNode ,
276
293
parentComponent : ComponentInternalInstance
@@ -325,17 +342,17 @@ function renderElement(
325
342
}
326
343
}
327
344
328
- function renderPortal (
345
+ function renderPortalVNode (
329
346
vnode : VNode ,
330
347
parentComponent : ComponentInternalInstance
331
348
) {
332
349
const target = vnode . props && vnode . props . target
333
350
if ( ! target ) {
334
- console . warn ( `[@vue/server-renderer] Portal is missing target prop.` )
351
+ console . error ( `[@vue/server-renderer] Portal is missing target prop.` )
335
352
return [ ]
336
353
}
337
354
if ( ! isString ( target ) ) {
338
- console . warn (
355
+ console . error (
339
356
`[@vue/server-renderer] Portal target must be a query selector string.`
340
357
)
341
358
return [ ]
@@ -367,18 +384,23 @@ async function resolvePortals(context: SSRContext) {
367
384
}
368
385
}
369
386
370
- async function renderSuspense (
387
+ async function renderSuspenseVNode (
371
388
vnode : VNode ,
372
389
parentComponent : ComponentInternalInstance
373
390
) : Promise < ResolvedSSRBuffer > {
374
391
const { content, fallback } = normalizeSuspenseChildren ( vnode )
375
392
try {
376
393
const { push, getBuffer } = createBuffer ( )
377
394
renderVNode ( push , content , parentComponent )
395
+ // await here so error can be caught
378
396
return await getBuffer ( )
379
- } catch {
380
- const { push, getBuffer } = createBuffer ( )
381
- renderVNode ( push , fallback , parentComponent )
382
- return getBuffer ( )
397
+ } catch ( e ) {
398
+ if ( e [ AsyncSetupErrorMarker ] ) {
399
+ const { push, getBuffer } = createBuffer ( )
400
+ renderVNode ( push , fallback , parentComponent )
401
+ return getBuffer ( )
402
+ } else {
403
+ throw e
404
+ }
383
405
}
384
406
}
0 commit comments