From: daiwei Date: Wed, 30 Jul 2025 06:39:56 +0000 (+0800) Subject: feat(hydration): handle consecutive if node X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f28cb2f678c793712c1c87328884d54e0592547b;p=thirdparty%2Fvuejs%2Fcore.git feat(hydration): handle consecutive if node --- diff --git a/packages/runtime-vapor/__tests__/hydration.spec.ts b/packages/runtime-vapor/__tests__/hydration.spec.ts index 54381d7e68..16b0889343 100644 --- a/packages/runtime-vapor/__tests__/hydration.spec.ts +++ b/packages/runtime-vapor/__tests__/hydration.spec.ts @@ -1269,6 +1269,26 @@ describe('Vapor Mode hydration', () => { expect(container.innerHTML).toBe(``) }) + test('consecutive if node', async () => { + const data = ref(true) + const { container } = await testHydration( + ``, + { Child: `` }, + data, + ) + expect(container.innerHTML).toBe(`
foo
`) + + data.value = false + await nextTick() + expect(container.innerHTML).toBe(``) + + data.value = true + await nextTick() + expect(container.innerHTML).toBe(`
foo
`) + }) + test('v-if/else-if/else chain on component - switch branches', async () => { const data = ref('a') const { container } = await testHydration( diff --git a/packages/runtime-vapor/src/dom/hydration.ts b/packages/runtime-vapor/src/dom/hydration.ts index 0d4a118f19..2802b2860d 100644 --- a/packages/runtime-vapor/src/dom/hydration.ts +++ b/packages/runtime-vapor/src/dom/hydration.ts @@ -20,6 +20,10 @@ export function setCurrentHydrationNode(node: Node | null): void { currentHydrationNode = node } +export function advanceHydrationNode(node: Node): void { + setCurrentHydrationNode(node.nextSibling || node.parentNode) +} + let isOptimized = false function performHydration( @@ -96,7 +100,7 @@ function adoptTemplateImpl(node: Node, template: string): Node | null { } } - currentHydrationNode = __next(node) + advanceHydrationNode(node) return node } @@ -194,12 +198,12 @@ export function isNonHydrationNode(node: Node): boolean { export function locateVaporFragmentAnchor( node: Node, anchorLabel: string, -): Comment | undefined { - let n = node.nextSibling - while (n) { - if (isComment(n, anchorLabel)) return n - n = n.nextSibling +): Comment | null { + while (node) { + if (isComment(node, anchorLabel)) return node + node = node.nextSibling! } + return null } export function isEmptyTextNode(node: Node): node is Text { diff --git a/packages/runtime-vapor/src/fragment.ts b/packages/runtime-vapor/src/fragment.ts index 50ce18bdb3..2f6d3b42ad 100644 --- a/packages/runtime-vapor/src/fragment.ts +++ b/packages/runtime-vapor/src/fragment.ts @@ -11,12 +11,12 @@ import { } from './block' import type { TransitionHooks } from '@vue/runtime-dom' import { + advanceHydrationNode, currentHydrationNode, isComment, isHydrating, locateHydrationNode, locateVaporFragmentAnchor, - setCurrentHydrationNode, } from './dom/hydration' import { applyTransitionHooks, @@ -60,12 +60,13 @@ export class DynamicFragment extends VaporFragment { */ forwarded?: boolean teardown?: () => void + anchorLabel?: string constructor(anchorLabel?: string) { super([]) if (isHydrating) { locateHydrationNode(anchorLabel === 'slot') - this.hydrate(anchorLabel!) + this.anchorLabel = anchorLabel } else { this.anchor = __DEV__ && anchorLabel ? createComment(anchorLabel) : createTextNode() @@ -74,12 +75,13 @@ export class DynamicFragment extends VaporFragment { update(render?: BlockFn, key: any = render): void { if (key === this.current) { + if (isHydrating) this.hydrate(this.anchorLabel!) return } this.current = key const prevSub = setActiveSub() - const parent = this.anchor.parentNode + const parent = isHydrating ? null : this.anchor.parentNode const transition = this.$transition const renderBranch = () => { if (render) { @@ -137,10 +139,8 @@ export class DynamicFragment extends VaporFragment { } } - if (isHydrating) { - setCurrentHydrationNode(this.anchor.nextSibling) - } setActiveSub(prevSub) + if (isHydrating) this.hydrate(this.anchorLabel!) } hydrate(label: string): void { @@ -161,6 +161,7 @@ export class DynamicFragment extends VaporFragment { throw new Error(`${label} fragment anchor node was not found.`) } } + advanceHydrationNode(this.anchor) } }