diff --git a/packages/server-renderer/__tests__/render.spec.ts b/packages/server-renderer/__tests__/render.spec.ts
index 705cb2a8b6f..1b1d6256e8c 100644
--- a/packages/server-renderer/__tests__/render.spec.ts
+++ b/packages/server-renderer/__tests__/render.spec.ts
@@ -873,6 +873,26 @@ function testRender(type: string, render: typeof renderToString) {
expect(html).toBe(`
hello
`)
})
+ test('serverPrefetch w/ async setup', async () => {
+ const msg = Promise.resolve('hello')
+ const app = createApp({
+ data() {
+ return {
+ msg: '',
+ }
+ },
+ async serverPrefetch() {
+ this.msg = await msg
+ },
+ render() {
+ return h('div', this.msg)
+ },
+ async setup() {},
+ })
+ const html = await render(app)
+ expect(html).toBe(`hello
`)
+ })
+
// #2763
test('error handling w/ async setup', async () => {
const fn = vi.fn()
diff --git a/packages/server-renderer/src/render.ts b/packages/server-renderer/src/render.ts
index 4744940e827..97179526456 100644
--- a/packages/server-renderer/src/render.ts
+++ b/packages/server-renderer/src/render.ts
@@ -94,21 +94,20 @@ export function renderComponentVNode(
const instance = createComponentInstance(vnode, parentComponent, null)
const res = setupComponent(instance, true /* isSSR */)
const hasAsyncSetup = isPromise(res)
- const prefetches = instance.sp /* LifecycleHooks.SERVER_PREFETCH */
+ let prefetches = instance.sp /* LifecycleHooks.SERVER_PREFETCH */
if (hasAsyncSetup || prefetches) {
- let p: Promise = hasAsyncSetup
- ? (res as Promise)
- : Promise.resolve()
- if (prefetches) {
- p = p
- .then(() =>
- Promise.all(
+ const p: Promise = Promise.resolve(res as Promise)
+ .then(() => {
+ // instance.sp may be null until an async setup resolves, so evaluate it here
+ if (hasAsyncSetup) prefetches = instance.sp
+ if (prefetches) {
+ return Promise.all(
prefetches.map(prefetch => prefetch.call(instance.proxy)),
- ),
- )
- // Note: error display is already done by the wrapped lifecycle hook function.
- .catch(NOOP)
- }
+ )
+ }
+ })
+ // Note: error display is already done by the wrapped lifecycle hook function.
+ .catch(NOOP)
return p.then(() => renderComponentSubTree(instance, slotScopeId))
} else {
return renderComponentSubTree(instance, slotScopeId)