Skip to content

Commit 4ace79a

Browse files
authored
fix(runtime-core): avoid retaining el on cached text vnodes during static traversal (#14419)
revert #14134 refix #14127
1 parent d7bcd85 commit 4ace79a

File tree

2 files changed

+47
-29
lines changed

2 files changed

+47
-29
lines changed

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

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,49 @@ describe('renderer: teleport', () => {
292292
expect(serializeInner(targetB)).toBe(`<div>teleported</div>`)
293293
})
294294

295+
test('move cached text nodes', async () => {
296+
document.body.innerHTML = ''
297+
const root = document.createElement('div')
298+
document.body.appendChild(root)
299+
300+
const to = ref('#teleport01')
301+
const disabled = ref(true)
302+
303+
const App = defineComponent({
304+
setup() {
305+
return { to, disabled, deferMode }
306+
},
307+
template: `
308+
<div id="teleport01">
309+
<Teleport :to="to" :defer="deferMode" :disabled="disabled">
310+
static text
311+
</Teleport>
312+
</div>
313+
<div id="teleport02"></div>
314+
`,
315+
})
316+
317+
domRender(h(App), root)
318+
await nextTick()
319+
320+
const target1 = root.querySelector('#teleport01') as HTMLElement
321+
const target2 = root.querySelector('#teleport02') as HTMLElement
322+
expect(target1.innerHTML).toBe(
323+
'<!--teleport start--> static text <!--teleport end-->',
324+
)
325+
expect(target2.innerHTML).toBe('')
326+
327+
to.value = '#teleport02'
328+
disabled.value = false
329+
330+
await nextTick()
331+
expect(target1.innerHTML).toBe('<!--teleport start--><!--teleport end-->')
332+
expect(target2.innerHTML).toContain('static text')
333+
334+
domRender(null, root)
335+
root.remove()
336+
})
337+
295338
test('should update children', async () => {
296339
const target = nodeOps.createElement('div')
297340
const root = nodeOps.createElement('div')

packages/runtime-core/src/renderer.ts

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -500,27 +500,7 @@ function baseCreateRenderer(
500500
} else {
501501
const el = (n2.el = n1.el!)
502502
if (n2.children !== n1.children) {
503-
// We don't inherit el for cached text nodes in `traverseStaticChildren`
504-
// to avoid retaining detached DOM nodes. However, the text node may be
505-
// changed during HMR. In this case we need to replace the old text node
506-
// with the new one.
507-
if (
508-
__DEV__ &&
509-
isHmrUpdating &&
510-
n2.patchFlag === PatchFlags.CACHED &&
511-
'__elIndex' in n1
512-
) {
513-
const childNodes = __TEST__
514-
? container.children
515-
: container.childNodes
516-
const newChild = hostCreateText(n2.children as string)
517-
const oldChild =
518-
childNodes[((n2 as any).__elIndex = (n1 as any).__elIndex)]
519-
hostInsert(newChild, container, oldChild)
520-
hostRemove(oldChild)
521-
} else {
522-
hostSetText(el, n2.children as string)
523-
}
503+
hostSetText(el, n2.children as string)
524504
}
525505
}
526506
}
@@ -2518,15 +2498,10 @@ export function traverseStaticChildren(
25182498
// #6852 also inherit for text nodes
25192499
if (c2.type === Text) {
25202500
// avoid cached text nodes retaining detached dom nodes
2521-
if (c2.patchFlag !== PatchFlags.CACHED) {
2522-
c2.el = c1.el
2523-
} else {
2524-
// cache the child index for HMR updates
2525-
;(c2 as any).__elIndex =
2526-
i +
2527-
// take fragment start anchor into account
2528-
(n1.type === Fragment ? 1 : 0)
2501+
if (c2.patchFlag === PatchFlags.CACHED) {
2502+
c2 = ch2[i] = cloneIfMounted(c2)
25292503
}
2504+
c2.el = c1.el
25302505
}
25312506
// #2324 also inherit for comment nodes, but not placeholders (e.g. v-if which
25322507
// would have received .el during block patch)

0 commit comments

Comments
 (0)