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)