Skip to content

Commit 5e37dd0

Browse files
authored
fix(hmr/teleport): adjust static children traversal for HMR in dev mode (#12819)
close #12816
1 parent 0b23fd2 commit 5e37dd0

File tree

2 files changed

+59
-1
lines changed

2 files changed

+59
-1
lines changed

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

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
markRaw,
1111
nextTick,
1212
nodeOps,
13+
onMounted,
1314
h as originalH,
1415
ref,
1516
render,
@@ -18,6 +19,10 @@ import {
1819
} from '@vue/runtime-test'
1920
import { Fragment, createCommentVNode, createVNode } from '../../src/vnode'
2021
import { compile, createApp as createDOMApp, render as domRender } from 'vue'
22+
import type { HMRRuntime } from '../../src/hmr'
23+
24+
declare var __VUE_HMR_RUNTIME__: HMRRuntime
25+
const { rerender, createRecord } = __VUE_HMR_RUNTIME__
2126

2227
describe('renderer: teleport', () => {
2328
describe('eager mode', () => {
@@ -741,4 +746,56 @@ describe('renderer: teleport', () => {
741746
expect(tRefInMounted).toBe(target.children[1])
742747
})
743748
}
749+
750+
test('handle update and hmr rerender', async () => {
751+
const target = document.createElement('div')
752+
const root = document.createElement('div')
753+
754+
const Comp = {
755+
setup() {
756+
const cls = ref('foo')
757+
onMounted(() => {
758+
// trigger update
759+
cls.value = 'bar'
760+
})
761+
return { cls, target }
762+
},
763+
template: `
764+
<Teleport :to="target">
765+
<div :class="cls">
766+
<div>
767+
<slot></slot>
768+
</div>
769+
</div>
770+
</Teleport>
771+
`,
772+
}
773+
774+
const appId = 'test-app-id'
775+
const App = {
776+
__hmrId: appId,
777+
components: { Comp },
778+
render() {
779+
return originalH(Comp, null, { default: () => originalH('div', 'foo') })
780+
},
781+
}
782+
createRecord(appId, App)
783+
784+
domRender(originalH(App), root)
785+
expect(target.innerHTML).toBe(
786+
'<div class="foo"><div><div>foo</div></div></div>',
787+
)
788+
await nextTick()
789+
expect(target.innerHTML).toBe(
790+
'<div class="bar"><div><div>foo</div></div></div>',
791+
)
792+
793+
rerender(appId, () =>
794+
originalH(Comp, null, { default: () => originalH('div', 'bar') }),
795+
)
796+
await nextTick()
797+
expect(target.innerHTML).toBe(
798+
'<div class="bar"><div><div>bar</div></div></div>',
799+
)
800+
})
744801
})

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,8 @@ export const TeleportImpl = {
220220
// even in block tree mode we need to make sure all root-level nodes
221221
// in the teleport inherit previous DOM references so that they can
222222
// be moved in future patches.
223-
traverseStaticChildren(n1, n2, true)
223+
// in dev mode, deep traversal is necessary for HMR
224+
traverseStaticChildren(n1, n2, !__DEV__)
224225
} else if (!optimized) {
225226
patchChildren(
226227
n1,

0 commit comments

Comments
 (0)