Skip to content

Commit c80ac2b

Browse files
committed
feat: onServerPrefetch
1 parent e79feb0 commit c80ac2b

File tree

3 files changed

+79
-2
lines changed

3 files changed

+79
-2
lines changed

packages/runtime-core/src/apiLifecycle.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
ComponentInternalInstance,
3+
ComponentOptions,
34
currentInstance,
45
isInSSRComponentSetup,
56
LifecycleHooks,
@@ -95,3 +96,31 @@ export const onErrorCaptured = (
9596
) => {
9697
injectHook(LifecycleHooks.ERROR_CAPTURED, hook, target)
9798
}
99+
100+
export function onServerPrefetch<
101+
T extends () => Promise<any> = () => Promise<unknown>
102+
>(handler: T) {
103+
const target = currentInstance
104+
if (target) {
105+
if (isInSSRComponentSetup) {
106+
const type = target.type as ComponentOptions
107+
let hook = type.serverPrefetch
108+
if (hook) {
109+
// Merge hook
110+
type.serverPrefetch = () => handler().then(() => (hook as Function)())
111+
} else {
112+
type.serverPrefetch = handler
113+
}
114+
}
115+
} else if (__DEV__) {
116+
warn(
117+
`onServerPrefetch is called when there is no active component instance to be ` +
118+
`associated with. ` +
119+
`Lifecycle injection APIs can only be used during execution of setup().` +
120+
(__FEATURE_SUSPENSE__
121+
? ` If you are using async setup(), make sure to register lifecycle ` +
122+
`hooks before the first await statement.`
123+
: ``)
124+
)
125+
}
126+
}

packages/runtime-core/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ export {
3737
onDeactivated,
3838
onRenderTracked,
3939
onRenderTriggered,
40-
onErrorCaptured
40+
onErrorCaptured,
41+
onServerPrefetch
4142
} from './apiLifecycle'
4243
export { provide, inject } from './apiInject'
4344
export { nextTick } from './scheduler'

packages/server-renderer/__tests__/render.spec.ts

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import {
88
ref,
99
defineComponent,
1010
createTextVNode,
11-
createStaticVNode
11+
createStaticVNode,
12+
onServerPrefetch
1213
} from 'vue'
1314
import { escapeHtml } from '@vue/shared'
1415
import { renderToString } from '../src/renderToString'
@@ -715,5 +716,51 @@ function testRender(type: string, render: typeof renderToString) {
715716
const html = await render(app)
716717
expect(html).toBe(`<div>hello</div>`)
717718
})
719+
720+
test('onServerPrefetch', async () => {
721+
const msg = Promise.resolve('hello')
722+
const app = createApp({
723+
setup() {
724+
const message = ref('')
725+
onServerPrefetch(async () => {
726+
message.value = await msg
727+
})
728+
return {
729+
message
730+
}
731+
},
732+
render() {
733+
return h('div', this.message)
734+
}
735+
})
736+
const html = await render(app)
737+
expect(html).toBe(`<div>hello</div>`)
738+
})
739+
740+
test('multiple onServerPrefetch', async () => {
741+
const msg = Promise.resolve('hello')
742+
const msg2 = Promise.resolve('hi')
743+
const app = createApp({
744+
setup() {
745+
const message = ref('')
746+
const message2 = ref('')
747+
onServerPrefetch(async () => {
748+
message.value = await msg
749+
})
750+
onServerPrefetch(async () => {
751+
message2.value = await msg2
752+
})
753+
return {
754+
message,
755+
message2
756+
}
757+
},
758+
render() {
759+
return h('div', `${this.message} ${this.message2}`)
760+
}
761+
})
762+
const html = await render(app)
763+
expect(html).toBe(`<div>hello hi</div>`)
764+
})
718765
})
719766
}

0 commit comments

Comments
 (0)