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

fix(compiler-vapor): resolve Suspense as built-in component

daiwei 1 месяц назад
Родитель
Сommit
c9fa193925
2 измененных файлов с 72 добавлено и 5 удалено
  1. 3 0
      packages/compiler-vapor/src/utils.ts
  2. 69 5
      packages/runtime-vapor/__tests__/hydration.spec.ts

+ 3 - 0
packages/compiler-vapor/src/utils.ts

@@ -153,6 +153,9 @@ export function isTeleportTag(tag: string): boolean {
 export function isBuiltInComponent(tag: string): string | undefined {
 export function isBuiltInComponent(tag: string): string | undefined {
   if (isTeleportTag(tag)) {
   if (isTeleportTag(tag)) {
     return 'VaporTeleport'
     return 'VaporTeleport'
+  } else if (tag === 'Suspense' || tag === 'suspense') {
+    // TODO: replace with VaporSuspense once it's implemented
+    return 'Suspense'
   } else if (isKeepAliveTag(tag)) {
   } else if (isKeepAliveTag(tag)) {
     return 'VaporKeepAlive'
     return 'VaporKeepAlive'
   } else if (isTransitionTag(tag)) {
   } else if (isTransitionTag(tag)) {

+ 69 - 5
packages/runtime-vapor/__tests__/hydration.spec.ts

@@ -5914,7 +5914,6 @@ describe('Vapor Mode hydration', () => {
           `
           `
           const appCode = `
           const appCode = `
             <script setup>
             <script setup>
-              import { Suspense } from 'vue'
               const components = _components
               const components = _components
             </script>
             </script>
             <template>
             <template>
@@ -5996,7 +5995,6 @@ describe('Vapor Mode hydration', () => {
           `
           `
           const appCode = `
           const appCode = `
             <script setup>
             <script setup>
-              import { Suspense } from 'vue'
               const components = _components
               const components = _components
             </script>
             </script>
             <template>
             <template>
@@ -6079,7 +6077,6 @@ describe('Vapor Mode hydration', () => {
           `
           `
           const appCode = `
           const appCode = `
             <script setup>
             <script setup>
-              import { Suspense } from 'vue'
               const components = _components
               const components = _components
             </script>
             </script>
             <template>
             <template>
@@ -6177,7 +6174,6 @@ describe('Vapor Mode hydration', () => {
           `
           `
           const appCode = `
           const appCode = `
             <script setup>
             <script setup>
-              import { Suspense } from 'vue'
               const data = _data
               const data = _data
               const components = _components
               const components = _components
             </script>
             </script>
@@ -6320,7 +6316,6 @@ describe('Vapor Mode hydration', () => {
           `
           `
           const appCode = `
           const appCode = `
             <script setup>
             <script setup>
-              import { Suspense } from 'vue'
               const data = _data
               const data = _data
               const components = _components
               const components = _components
             </script>
             </script>
@@ -9321,6 +9316,75 @@ describe('VDOM interop', () => {
     `)
     `)
   })
   })
 
 
+  test('hydrate static Suspense with vapor child before trailing sibling', async () => {
+    const serverData = ref({
+      tail: 'tail',
+    })
+    const clientData = ref({
+      html: '',
+      tail: 'tail',
+    })
+    const appCode = `<script setup>
+        const data = _data
+        const components = _components
+      </script>
+      <template>
+        <div>
+          <p>before</p>
+          <Suspense>
+            <components.Child />
+            <template #fallback></template>
+          </Suspense>
+          <span>{{ data.tail }}</span>
+        </div>
+      </template>`
+    const serverChildCode = `<div id="dmermaid"><svg></svg></div>`
+    const clientChildCode = `<script setup>
+            const data = _data
+          </script>
+          <template><div v-html="data.html"></div></template>`
+
+    const SSRChild = compileVaporComponent(
+      serverChildCode,
+      serverData,
+      undefined,
+      true,
+    )
+    const SSRApp = compileVaporComponent(
+      appCode,
+      serverData,
+      { Child: SSRChild },
+      true,
+    )
+    const html = await VueServerRenderer.renderToString(
+      runtimeDom.createSSRApp(SSRApp),
+    )
+
+    const ClientChild = compileVaporComponent(clientChildCode, clientData)
+    const ClientApp = compileVaporComponent(appCode, clientData, {
+      Child: ClientChild,
+    })
+    const container = document.createElement('div')
+    container.innerHTML = html
+    document.body.appendChild(container)
+    const app = createVaporSSRApp(ClientApp)
+    app.use(runtimeVapor.vaporInteropPlugin)
+    app.mount(container)
+
+    expect(`Hydration node mismatch`).not.toHaveBeenWarned()
+    expect(formatHtml(container.innerHTML)).toMatchInlineSnapshot(`
+      "<div><p>before</p><div id="dmermaid"><svg></svg></div><span>tail</span></div>"
+    `)
+
+    clientData.value.html = '<svg data-updated="true"></svg>'
+    clientData.value.tail = 'tail-updated'
+    await nextTick()
+
+    expect(formatHtml(container.innerHTML)).toMatchInlineSnapshot(`
+      "<div><p>before</p><div id="dmermaid"><svg data-updated="true"></svg></div><span>tail-updated</span></div>"
+    `)
+  })
+
   test('hydrate async Suspense VNode via createDynamicComponent and show fallback', async () => {
   test('hydrate async Suspense VNode via createDynamicComponent and show fallback', async () => {
     const data = ref({
     const data = ref({
       showSuspense: true,
       showSuspense: true,