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