From 913af4c5438556988cd24ce3b0df8b74a1ab9c73 Mon Sep 17 00:00:00 2001 From: daiwei Date: Sat, 1 Feb 2025 11:28:21 +0800 Subject: [PATCH 1/3] fix(hydration): handle v-if node mismatch --- packages/runtime-core/__tests__/hydration.spec.ts | 10 ++++++++++ packages/runtime-core/src/hydration.ts | 14 +++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/runtime-core/__tests__/hydration.spec.ts b/packages/runtime-core/__tests__/hydration.spec.ts index 56011d06359..8daf68c27c8 100644 --- a/packages/runtime-core/__tests__/hydration.spec.ts +++ b/packages/runtime-core/__tests__/hydration.spec.ts @@ -2299,6 +2299,16 @@ describe('SSR hydration', () => { expect(`Hydration node mismatch`).not.toHaveBeenWarned() }) + test('comment mismatch (v-if)', () => { + const { container } = mountWithHydration(``, () => + h('div', { 'data-allow-mismatch': '' }, [h('span', 'value')]), + ) + expect(container.innerHTML).toBe( + '
value
', + ) + expect(`Hydration node mismatch`).not.toHaveBeenWarned() + }) + test('comment mismatch (text)', () => { const { container } = mountWithHydration( `
foobar
`, diff --git a/packages/runtime-core/src/hydration.ts b/packages/runtime-core/src/hydration.ts index a94ff356810..aa94eb09619 100644 --- a/packages/runtime-core/src/hydration.ts +++ b/packages/runtime-core/src/hydration.ts @@ -675,7 +675,10 @@ export function createHydrationFunctions( slotScopeIds: string[] | null, isFragment: boolean, ): Node | null => { - if (!isMismatchAllowed(node.parentElement!, MismatchTypes.CHILDREN)) { + if ( + !isMismatchAllowed(node.parentElement!, MismatchTypes.CHILDREN) && + !isCommentNodeMismatch(node, vnode) + ) { ;(__DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__) && warn( `Hydration node mismatch:\n- rendered on server:`, @@ -993,3 +996,12 @@ function isMismatchAllowed( return allowedAttr.split(',').includes(MismatchTypeString[allowedType]) } } + +// data-allow-mismatch + v-if +function isCommentNodeMismatch(node: Node, vnode: VNode): boolean { + if (node.nodeType !== DOMNodeTypes.COMMENT || !vnode.props) { + return false + } + + return allowMismatchAttr in vnode.props +} From b7e11639d5efb32e1fecd4b99ce7df36b4268217 Mon Sep 17 00:00:00 2001 From: daiwei Date: Sat, 1 Feb 2025 11:37:03 +0800 Subject: [PATCH 2/3] chore: update --- packages/runtime-core/src/hydration.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/runtime-core/src/hydration.ts b/packages/runtime-core/src/hydration.ts index aa94eb09619..bc938b58775 100644 --- a/packages/runtime-core/src/hydration.ts +++ b/packages/runtime-core/src/hydration.ts @@ -19,6 +19,7 @@ import { ShapeFlags, def, getEscapedCssVarName, + hasOwn, includeBooleanAttr, isBooleanAttr, isKnownHtmlAttr, @@ -677,7 +678,7 @@ export function createHydrationFunctions( ): Node | null => { if ( !isMismatchAllowed(node.parentElement!, MismatchTypes.CHILDREN) && - !isCommentNodeMismatch(node, vnode) + !isMismatchAllowedForCommentNode(node, vnode) ) { ;(__DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__) && warn( @@ -998,10 +999,13 @@ function isMismatchAllowed( } // data-allow-mismatch + v-if -function isCommentNodeMismatch(node: Node, vnode: VNode): boolean { - if (node.nodeType !== DOMNodeTypes.COMMENT || !vnode.props) { - return false - } - - return allowMismatchAttr in vnode.props +function isMismatchAllowedForCommentNode( + node: Node, + { props }: VNode, +): boolean { + return ( + node.nodeType === DOMNodeTypes.COMMENT && + props != null && + hasOwn(props, allowMismatchAttr) + ) } From b2efba8ff0cee3379c66ff0d4be39628952ed71f Mon Sep 17 00:00:00 2001 From: daiwei Date: Sat, 1 Feb 2025 11:41:27 +0800 Subject: [PATCH 3/3] chore: update --- packages/runtime-core/src/hydration.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/runtime-core/src/hydration.ts b/packages/runtime-core/src/hydration.ts index bc938b58775..3977b45a1d2 100644 --- a/packages/runtime-core/src/hydration.ts +++ b/packages/runtime-core/src/hydration.ts @@ -1003,9 +1003,5 @@ function isMismatchAllowedForCommentNode( node: Node, { props }: VNode, ): boolean { - return ( - node.nodeType === DOMNodeTypes.COMMENT && - props != null && - hasOwn(props, allowMismatchAttr) - ) + return isComment(node) && props != null && hasOwn(props, allowMismatchAttr) }