소스 검색

fix(hydration): respect text allow-mismatch during multi-root hydration cleanup

daiwei 1 주 전
부모
커밋
b928e8ae19
2개의 변경된 파일73개의 추가작업 그리고 8개의 파일을 삭제
  1. 62 0
      packages/runtime-vapor/__tests__/hydration.spec.ts
  2. 11 8
      packages/runtime-vapor/src/dom/prop.ts

+ 62 - 0
packages/runtime-vapor/__tests__/hydration.spec.ts

@@ -9826,6 +9826,68 @@ describe('VDOM interop', () => {
     )
   })
 
+  test('hydrate multi-root Vapor component should cleanup extra SSR text within allow-mismatch wrapper', async () => {
+    const data = ref({
+      msg: 'Hello',
+      extra: 'Tail',
+      after: 'After',
+    })
+
+    const childCode = `<script setup>
+        const data = _data
+      </script>
+      <template>
+        <span>{{ data.msg }}</span>{{ data.extra }}
+      </template>`
+
+    const appCode = `<script setup>
+        const components = _components
+        const data = _data
+      </script>
+      <template>
+        <div data-allow-mismatch="text">
+          <components.Child />
+          <span>{{ data.after }}</span>
+        </div>
+      </template>`
+
+    const SSRChild = compileVaporComponent(childCode, data, undefined, true)
+    const SSRApp = compileVaporComponent(
+      appCode,
+      data,
+      { Child: SSRChild },
+      true,
+    )
+    const html = await VueServerRenderer.renderToString(
+      runtimeDom.createSSRApp(SSRApp),
+    )
+
+    data.value.extra = ''
+
+    const ClientChild = compileVaporComponent(childCode, data)
+    const ClientApp = compileVaporComponent(appCode, data, {
+      Child: ClientChild,
+    })
+
+    const container = document.createElement('div')
+    container.innerHTML = html
+    document.body.appendChild(container)
+    createVaporSSRApp(ClientApp).mount(container)
+
+    expect(`Hydration text mismatch`).not.toHaveBeenWarned()
+    expect(container.innerHTML).toBe(
+      '<div data-allow-mismatch="text"><!--[--><span>Hello</span><!--]--><span>After</span></div>',
+    )
+
+    data.value.extra = 'Updated'
+    data.value.after = 'After updated'
+    await nextTick()
+
+    expect(container.innerHTML).toBe(
+      '<div data-allow-mismatch="text"><!--[--><span>Hello</span>Updated<!--]--><span>After updated</span></div>',
+    )
+  })
+
   test('hydrate multi-root VDOM via mountVNode as non-first child', async () => {
     const MultiRootVDOM = {
       setup() {

+ 11 - 8
packages/runtime-vapor/src/dom/prop.ts

@@ -346,14 +346,17 @@ export function setText(el: Text & { $txt?: string }, value: string): void {
       return
     }
 
-    ;(__DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__) &&
-      warn(
-        `Hydration text mismatch in`,
-        el.parentNode,
-        `\n  - rendered on server: ${JSON.stringify((el as Text).data)}` +
-          `\n  - expected on client: ${JSON.stringify(value)}`,
-      )
-    logMismatchError()
+    const parent = el.parentElement
+    if (parent && !isMismatchAllowed(parent, MismatchTypes.TEXT)) {
+      ;(__DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__) &&
+        warn(
+          `Hydration text mismatch in`,
+          el.parentNode,
+          `\n  - rendered on server: ${JSON.stringify((el as Text).data)}` +
+            `\n  - expected on client: ${JSON.stringify(value)}`,
+        )
+      logMismatchError()
+    }
   }
 
   if (el.$txt !== value) {