]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(useId): ensure useId consistency when using serverPrefetch (#12128)
authoryangxiuxiu <79584569+yangxiuxiu1115@users.noreply.github.com>
Fri, 11 Oct 2024 02:49:14 +0000 (10:49 +0800)
committerGitHub <noreply@github.com>
Fri, 11 Oct 2024 02:49:14 +0000 (10:49 +0800)
close #12102

packages/runtime-core/__tests__/helpers/useId.spec.ts
packages/runtime-core/src/component.ts

index d71260cdaffba7129049709627d8e341c9e62cc8..3860d43db20bc3a43582c3718535f592d4ac2b40 100644 (file)
@@ -8,6 +8,7 @@ import {
   defineAsyncComponent,
   defineComponent,
   h,
+  onServerPrefetch,
   useId,
 } from 'vue'
 import { renderToString } from '@vue/server-renderer'
@@ -145,6 +146,40 @@ describe('useId', () => {
     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,
index a1ce1de4eb995b1de4a09f456dc2b2a84da8cb40..939f5a401f0a33da5e009fdb984f4d3cbaea303a 100644 (file)
@@ -856,11 +856,10 @@ function setupStatefulComponent(
   // 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,
@@ -870,12 +869,16 @@ function setupStatefulComponent(
         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