Просмотр исходного кода

fix(runtime-vapor): hydrate forwarded empty interop slot fragments in place

daiwei 1 неделя назад
Родитель
Сommit
5cc1732205

+ 1 - 1
packages/runtime-core/src/index.ts

@@ -609,7 +609,7 @@ export { setRef } from './rendererTemplateRef'
 /**
  * @internal
  */
-export { type VNodeNormalizedRef, normalizeRef } from './vnode'
+export { VaporSlot, type VNodeNormalizedRef, normalizeRef } from './vnode'
 /**
  * @internal
  */

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

@@ -3493,6 +3493,51 @@ describe('Vapor Mode hydration', () => {
       )
     })
 
+    test('forwarded empty named slot with trailing sibling nodes', async () => {
+      const { container } = await testHydration(
+        `<template>
+          <components.Layout>
+            <template #banner>
+              <div>banner</div>
+            </template>
+            <template #footer-before>
+              <slot name="footer-before" />
+            </template>
+          </components.Layout>
+        </template>`,
+        {
+          Layout: `<template>
+            <div>
+              <slot name="banner" />
+              <components.Page>
+                <template #footer-before>
+                  <slot name="footer-before" />
+                </template>
+              </components.Page>
+            </div>
+          </template>`,
+          Page: `<template>
+            <div>
+              <main><span>content</span></main>
+              <slot name="footer-before" />
+              <p>footer</p>
+            </div>
+          </template>`,
+        },
+      )
+
+      expect(formatHtml(container.innerHTML)).toMatchInlineSnapshot(
+        `
+      	"<div>
+      	<!--[--><div>banner</div><!--]-->
+      	<div><main><span>content</span></main>
+      	<!--[--><!--]-->
+      	<!--slot--><!--slot--><p>footer</p></div></div>"
+      `,
+      )
+      expect(`Hydration node mismatch`).not.toHaveBeenWarned()
+    })
+
     test('forwarded named slot can appear after hydrating as empty', async () => {
       const data = reactive({
         show: false,
@@ -10397,4 +10442,61 @@ describe('VDOM interop', () => {
     )
     expect(`Hydration node mismatch`).not.toHaveBeenWarned()
   })
+
+  test('hydrate forwarded empty named VDOM slot with trailing sibling nodes', async () => {
+    const { container } = await testWithVaporApp(
+      `<script setup>
+        const components = _components
+      </script>
+      <template>
+        <components.Layout>
+          <template #banner>
+            <div>banner</div>
+          </template>
+          <template #footer-before>
+            <slot name="footer-before" />
+          </template>
+        </components.Layout>
+      </template>`,
+      {
+        Layout: {
+          code: `<script setup>
+            const components = _components
+          </script>
+          <template>
+            <div>
+              <slot name="banner" />
+              <components.Page>
+                <template #footer-before>
+                  <slot name="footer-before" />
+                </template>
+              </components.Page>
+            </div>
+          </template>`,
+          vapor: false,
+        },
+        Page: {
+          code: `<template>
+            <div>
+              <main><span>content</span></main>
+              <slot name="footer-before" />
+              <p>footer</p>
+            </div>
+          </template>`,
+          vapor: false,
+        },
+      },
+    )
+
+    expect(formatHtml(container.innerHTML)).toMatchInlineSnapshot(
+      `
+      "<div>
+      <!--[--><div>banner</div><!--]-->
+      <div><main><span>content</span></main>
+      <!--[--><!--]-->
+      <!--slot--><p>footer</p></div></div>"
+      `,
+    )
+    expect(`Hydration node mismatch`).not.toHaveBeenWarned()
+  })
 })

+ 1 - 0
packages/vue/src/index-with-vapor.ts

@@ -1,4 +1,5 @@
 // for type generation only
 export * from './index'
 export * from '@vue/runtime-vapor'
+export type { VaporSlot } from '@vue/runtime-vapor'
 export { withAsyncContext } from '@vue/runtime-vapor'

+ 1 - 0
packages/vue/src/runtime-with-vapor.ts

@@ -1,3 +1,4 @@
 export * from './runtime'
 export * from '@vue/runtime-vapor'
+export type { VaporSlot } from '@vue/runtime-vapor'
 export { withAsyncContext } from '@vue/runtime-vapor'