Browse Source

fix(runtime-vapor): force defer mount when teleport has insertion state (#14049)

edison 5 months ago
parent
commit
b005811f65

+ 39 - 0
packages/runtime-vapor/__tests__/components/Teleport.spec.ts

@@ -192,6 +192,7 @@ describe('renderer: VaporTeleport', () => {
       expect(root.innerHTML).toBe(
         '<!--teleport start--><!--teleport end--><div>root 2</div>',
       )
+      await nextTick()
       expect(target.innerHTML).toBe('<div>teleported 2</div>')
     })
 
@@ -367,6 +368,7 @@ describe('renderer: VaporTeleport', () => {
       expect(root.innerHTML).toBe(
         '<!--teleport start--><!--teleport end--><div>root 2</div>',
       )
+      await nextTick()
       expect(target.innerHTML).toBe('<div>teleported 2</div>')
 
       // reload parent again by changing disabled
@@ -1255,4 +1257,41 @@ function runSharedTests(deferMode: boolean): void {
     expect(child.outerHTML).toBe(`<div>teleported</div>`)
     expect(tRefInMounted).toBe(child)
   })
+
+  test('with insertion state', async () => {
+    const root = document.createElement('div')
+    document.body.appendChild(root)
+
+    const Comp = defineVaporComponent({
+      setup() {
+        return template('content')()
+      },
+    })
+
+    const { app, mount } = define({
+      setup() {
+        const n0 = template('<div id="tt"></div>')()
+        const n4 = template('<div></div>')() as any
+        setInsertionState(n4, null, true)
+        createComponent(
+          VaporTeleport,
+          { to: () => '#tt' },
+          {
+            default: () =>
+              createComponent(Comp, null, {
+                default: () => template('content')(),
+              }),
+          },
+        )
+        return [n0, n4]
+      },
+    }).create()
+
+    mount(root)
+
+    await nextTick()
+    const target = document.querySelector('#tt')!
+    expect(target.innerHTML).toBe('content')
+    app.unmount()
+  })
 }

+ 6 - 1
packages/runtime-vapor/src/components/Teleport.ts

@@ -165,7 +165,12 @@ export class TeleportFragment extends VaporFragment {
     }
     // mount into target container
     else {
-      if (isTeleportDeferred(this.resolvedProps!)) {
+      if (
+        isTeleportDeferred(this.resolvedProps!) ||
+        // force defer when the parent is not connected to the DOM,
+        // typically due to an early insertion caused by setInsertionState.
+        !this.parent!.isConnected
+      ) {
         queuePostFlushCb(mountToTarget)
       } else {
         mountToTarget()