]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(hmr/teleport): adjust static children traversal for HMR in dev mode (#12819)
authoredison <daiwei521@126.com>
Fri, 2 May 2025 09:18:01 +0000 (17:18 +0800)
committerGitHub <noreply@github.com>
Fri, 2 May 2025 09:18:01 +0000 (02:18 -0700)
close #12816

packages/runtime-core/__tests__/components/Teleport.spec.ts
packages/runtime-core/src/components/Teleport.ts

index 79125cd04dfdccf918e27643e36d53e930e6586d..1229c5325b7fe95957376efc8f3ee37077d95004 100644 (file)
@@ -10,6 +10,7 @@ import {
   markRaw,
   nextTick,
   nodeOps,
+  onMounted,
   h as originalH,
   ref,
   render,
@@ -18,6 +19,10 @@ import {
 } from '@vue/runtime-test'
 import { Fragment, createCommentVNode, createVNode } from '../../src/vnode'
 import { compile, createApp as createDOMApp, render as domRender } from 'vue'
+import type { HMRRuntime } from '../../src/hmr'
+
+declare var __VUE_HMR_RUNTIME__: HMRRuntime
+const { rerender, createRecord } = __VUE_HMR_RUNTIME__
 
 describe('renderer: teleport', () => {
   describe('eager mode', () => {
@@ -741,4 +746,56 @@ describe('renderer: teleport', () => {
       expect(tRefInMounted).toBe(target.children[1])
     })
   }
+
+  test('handle update and hmr rerender', async () => {
+    const target = document.createElement('div')
+    const root = document.createElement('div')
+
+    const Comp = {
+      setup() {
+        const cls = ref('foo')
+        onMounted(() => {
+          // trigger update
+          cls.value = 'bar'
+        })
+        return { cls, target }
+      },
+      template: `
+        <Teleport :to="target">
+          <div :class="cls">
+            <div>
+              <slot></slot>
+            </div>
+          </div>
+        </Teleport>
+      `,
+    }
+
+    const appId = 'test-app-id'
+    const App = {
+      __hmrId: appId,
+      components: { Comp },
+      render() {
+        return originalH(Comp, null, { default: () => originalH('div', 'foo') })
+      },
+    }
+    createRecord(appId, App)
+
+    domRender(originalH(App), root)
+    expect(target.innerHTML).toBe(
+      '<div class="foo"><div><div>foo</div></div></div>',
+    )
+    await nextTick()
+    expect(target.innerHTML).toBe(
+      '<div class="bar"><div><div>foo</div></div></div>',
+    )
+
+    rerender(appId, () =>
+      originalH(Comp, null, { default: () => originalH('div', 'bar') }),
+    )
+    await nextTick()
+    expect(target.innerHTML).toBe(
+      '<div class="bar"><div><div>bar</div></div></div>',
+    )
+  })
 })
index fe6fa36c1ca4a5730589b10ba8bcf359238c1742..fc2ee4c086f64eb199cfd1bbf15d5ecdb975b04b 100644 (file)
@@ -220,7 +220,8 @@ export const TeleportImpl = {
         // even in block tree mode we need to make sure all root-level nodes
         // in the teleport inherit previous DOM references so that they can
         // be moved in future patches.
-        traverseStaticChildren(n1, n2, true)
+        // in dev mode, deep traversal is necessary for HMR
+        traverseStaticChildren(n1, n2, !__DEV__)
       } else if (!optimized) {
         patchChildren(
           n1,