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 +}