From: daiwei Date: Thu, 31 Jul 2025 01:28:18 +0000 (+0800) Subject: feat(hydration): handle consecutive prepend X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6606cbdb4b0b2b7922cd0e18ee5331fbfe5d7462;p=thirdparty%2Fvuejs%2Fcore.git feat(hydration): handle consecutive prepend --- diff --git a/packages/runtime-vapor/__tests__/hydration.spec.ts b/packages/runtime-vapor/__tests__/hydration.spec.ts index e854a19360..8bc7689e32 100644 --- a/packages/runtime-vapor/__tests__/hydration.spec.ts +++ b/packages/runtime-vapor/__tests__/hydration.spec.ts @@ -2511,6 +2511,56 @@ describe('Vapor Mode hydration', () => { ) }) + test('consecutive slots prepend', async () => { + const data = reactive({ + msg1: 'foo', + msg2: 'bar', + msg3: 'baz', + }) + + const { container } = await testHydration( + ``, + { + Child: ``, + }, + data, + ) + + expect(container.innerHTML).toBe( + `
` + + `foo` + + `bar` + + `
baz
` + + `
`, + ) + + data.msg1 = 'hello' + data.msg2 = 'vapor' + await nextTick() + expect(container.innerHTML).toBe( + `
` + + `hello` + + `vapor` + + `
baz
` + + `
`, + ) + }) + test('slot fallback', async () => { const data = reactive({ foo: 'foo', diff --git a/packages/runtime-vapor/src/dom/hydration.ts b/packages/runtime-vapor/src/dom/hydration.ts index e551d93938..f90f153a2a 100644 --- a/packages/runtime-vapor/src/dom/hydration.ts +++ b/packages/runtime-vapor/src/dom/hydration.ts @@ -7,6 +7,7 @@ import { } from '../insertionState' import { __next, + __nthChild, _nthChild, disableHydrationNodeLookup, enableHydrationNodeLookup, @@ -39,6 +40,7 @@ function performHydration( // optimize anchor cache lookup ;(Comment.prototype as any).$fe = undefined ;(Node.prototype as any).$dp = undefined + ;(Node.prototype as any).$np = undefined isOptimized = true } enableHydrationNodeLookup() @@ -122,7 +124,9 @@ function locateHydrationNodeImpl(isFragment?: boolean): void { let node: Node | null // prepend / firstChild if (insertionAnchor === 0) { - node = insertionParent!.firstChild + const n = insertionParent!.$np || 0 + node = __nthChild(insertionParent!, n) + insertionParent!.$np = n + 1 } else if (insertionAnchor) { // `insertionAnchor` is a Node, it is the DOM node to hydrate // Template: `......`// `insertionAnchor` is the placeholder diff --git a/packages/runtime-vapor/src/insertionState.ts b/packages/runtime-vapor/src/insertionState.ts index 5c8ba4262e..f76ceb8b11 100644 --- a/packages/runtime-vapor/src/insertionState.ts +++ b/packages/runtime-vapor/src/insertionState.ts @@ -12,6 +12,10 @@ export let insertionParent: // const n4 = t0(2) // n4.$dp = 2 // The first 2 nodes are static, dynamic nodes start from index 2 $dp?: number + // number of prepends - hydration only + // consecutive prepends need to skip nodes that were prepended earlier + // each prepend increases the value of $prepend + $np?: number }) | undefined export let insertionAnchor: Node | 0 | undefined