]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(hydration): fix SFC style v-bind hydration mismatch warnings (#10250)
authoryangxiuxiu <79584569+yangxiuxiu1115@users.noreply.github.com>
Tue, 6 Feb 2024 09:38:41 +0000 (17:38 +0800)
committerGitHub <noreply@github.com>
Tue, 6 Feb 2024 09:38:41 +0000 (17:38 +0800)
close #10215

packages/runtime-core/__tests__/hydration.spec.ts
packages/runtime-core/src/component.ts
packages/runtime-core/src/hydration.ts
packages/runtime-dom/src/helpers/useCssVars.ts

index 127c0d88c7f8d4411cc9c454b7eccbff7675f605..3fa0d7e732ec280df05b0d113d856de5a4f937b7 100644 (file)
@@ -19,6 +19,7 @@ import {
   onMounted,
   ref,
   renderSlot,
+  useCssVars,
   vModelCheckbox,
   vShow,
   withDirectives,
@@ -1538,5 +1539,20 @@ describe('SSR hydration', () => {
       )
       expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
     })
+
+    test('should not warn css v-bind', () => {
+      const container = document.createElement('div')
+      container.innerHTML = `<div style="--foo:red;color:var(--foo);" />`
+      const app = createSSRApp({
+        setup() {
+          useCssVars(() => ({
+            foo: 'red',
+          }))
+          return () => h('div', { style: { color: 'var(--foo)' } })
+        },
+      })
+      app.mount(container)
+      expect(`Hydration style mismatch`).not.toHaveBeenWarned()
+    })
   })
 })
index 1508627e579faa65c44c05c1ee2b89f7552c4037..ed1f8efee52d4acb46f4122f987991aed9f7faea 100644 (file)
@@ -519,6 +519,12 @@ export interface ComponentInternalInstance {
    * @internal
    */
   ut?: (vars?: Record<string, string>) => void
+
+  /**
+   * dev only. For style v-bind hydration mismatch checks
+   * @internal
+   */
+  getCssVars?: () => Record<string, string>
 }
 
 const emptyAppContext = createAppContext()
index b22afdb7aa5e78ad8c742965adcf4e8b91c4433e..1e9200ce27b943c00d87ce2d0243adc4c5a8cbb4 100644 (file)
@@ -449,7 +449,10 @@ export function createHydrationFunctions(
         ) {
           for (const key in props) {
             // check hydration mismatch
-            if (__DEV__ && propHasMismatch(el, key, props[key], vnode)) {
+            if (
+              __DEV__ &&
+              propHasMismatch(el, key, props[key], vnode, parentComponent)
+            ) {
               hasMismatch = true
             }
             if (
@@ -718,6 +721,7 @@ function propHasMismatch(
   key: string,
   clientValue: any,
   vnode: VNode,
+  instance: ComponentInternalInstance | null,
 ): boolean {
   let mismatchType: string | undefined
   let mismatchKey: string | undefined
@@ -748,6 +752,12 @@ function propHasMismatch(
         }
       }
     }
+
+    const cssVars = instance?.getCssVars?.()
+    for (const key in cssVars) {
+      expectedMap.set(`--${key}`, String(cssVars[key]))
+    }
+
     if (!isMapEqual(actualMap, expectedMap)) {
       mismatchType = mismatchKey = 'style'
     }
index 72714e6f623fd0c7f87a98c4fa71c26d04940078..1666e3cb3dce5d77b14403ea723ad5df6fd9eecb 100644 (file)
@@ -32,6 +32,10 @@ export function useCssVars(getter: (ctx: any) => Record<string, string>) {
     ).forEach(node => setVarsOnNode(node, vars))
   })
 
+  if (__DEV__) {
+    instance.getCssVars = () => getter(instance.proxy)
+  }
+
   const setVars = () => {
     const vars = getter(instance.proxy)
     setVarsOnVNode(instance.subTree, vars)