diff --git a/packages/runtime-core/__tests__/hydration.spec.ts b/packages/runtime-core/__tests__/hydration.spec.ts index 3fa0d7e732e..de2d4fcb189 100644 --- a/packages/runtime-core/__tests__/hydration.spec.ts +++ b/packages/runtime-core/__tests__/hydration.spec.ts @@ -1554,5 +1554,21 @@ describe('SSR hydration', () => { app.mount(container) expect(`Hydration style mismatch`).not.toHaveBeenWarned() }) + + test('css vars should only be added to expected on component root dom', () => { + const container = document.createElement('div') + container.innerHTML = `
` + const app = createSSRApp({ + setup() { + useCssVars(() => ({ + foo: 'red', + })) + return () => + h('div', null, [h('div', { style: { color: 'var(--foo)' } })]) + }, + }) + app.mount(container) + expect(`Hydration style mismatch`).not.toHaveBeenWarned() + }) }) }) diff --git a/packages/runtime-core/src/hydration.ts b/packages/runtime-core/src/hydration.ts index 1e9200ce27b..fa61ed96a94 100644 --- a/packages/runtime-core/src/hydration.ts +++ b/packages/runtime-core/src/hydration.ts @@ -753,9 +753,11 @@ function propHasMismatch( } } - const cssVars = instance?.getCssVars?.() - for (const key in cssVars) { - expectedMap.set(`--${key}`, String(cssVars[key])) + if (instance && isInstanceRootEl(instance.subTree, el)) { + const cssVars = instance?.getCssVars?.() + for (const key in cssVars) { + expectedMap.set(`--${key}`, String(cssVars[key])) + } } if (!isMapEqual(actualMap, expectedMap)) { @@ -852,3 +854,25 @@ function isMapEqual(a: Map, b: Map): boolean { } return true } + +function isInstanceRootEl(vnode: VNode, element: Element): boolean { + while (vnode.component) { + vnode = vnode.component.subTree + } + + if (vnode.shapeFlag & ShapeFlags.ELEMENT && vnode.el) { + return element === vnode.el + } else if (vnode.type === Fragment) { + return (vnode.children as VNode[]).some(c => isInstanceRootEl(c, element)) + } else if (vnode.type === Static) { + let { el, anchor } = vnode + while (el) { + if (el === element) { + return true + } + if (el === anchor) break + el = el.nextSibling + } + } + return false +}