defineAsyncComponent,
defineComponent,
h,
+ onServerPrefetch,
useId,
} from 'vue'
import { renderToString } from '@vue/server-renderer'
expect(await getOutput(() => factory(16, 0))).toBe(expected)
})
+ test('components with serverPrefetch', async () => {
+ const factory = (): ReturnType<TestCaseFactory> => {
+ const SPOne = defineComponent({
+ setup() {
+ onServerPrefetch(() => {})
+ return () => h(BasicComponentWithUseId)
+ },
+ })
+
+ const SPTwo = defineComponent({
+ render() {
+ return h(BasicComponentWithUseId)
+ },
+ })
+
+ const app = createApp({
+ setup() {
+ const id1 = useId()
+ const id2 = useId()
+ return () => [id1, ' ', id2, ' ', h(SPOne), ' ', h(SPTwo)]
+ },
+ })
+ return [app, []]
+ }
+
+ const expected =
+ 'v-0 v-1 ' + // root
+ 'v-0-0 v-0-1 ' + // inside first async subtree
+ 'v-2 v-3' // inside second async subtree
+ // assert different async resolution order does not affect id stable-ness
+ expect(await getOutput(() => factory())).toBe(expected)
+ expect(await getOutput(() => factory())).toBe(expected)
+ })
+
test('async setup()', async () => {
const factory = (
delay1: number,
// 2. call setup()
const { setup } = Component
if (setup) {
+ pauseTracking()
const setupContext = (instance.setupContext =
setup.length > 1 ? createSetupContext(instance) : null)
-
const reset = setCurrentInstance(instance)
- pauseTracking()
const setupResult = callWithErrorHandling(
setup,
instance,
setupContext,
],
)
+ const isAsyncSetup = isPromise(setupResult)
resetTracking()
reset()
- if (isPromise(setupResult)) {
- // async setup, mark as async boundary for useId()
- if (!isAsyncWrapper(instance)) markAsyncBoundary(instance)
+ if ((isAsyncSetup || instance.sp) && !isAsyncWrapper(instance)) {
+ // async setup / serverPrefetch, mark as async boundary for useId()
+ markAsyncBoundary(instance)
+ }
+
+ if (isAsyncSetup) {
setupResult.then(unsetCurrentInstance, unsetCurrentInstance)
if (isSSR) {
// return the promise so server-renderer can wait on it