diff --git a/packages/runtime-core/__tests__/components/Teleport.spec.ts b/packages/runtime-core/__tests__/components/Teleport.spec.ts
index 79125cd04df..4739a17d534 100644
--- a/packages/runtime-core/__tests__/components/Teleport.spec.ts
+++ b/packages/runtime-core/__tests__/components/Teleport.spec.ts
@@ -13,10 +13,19 @@ import {
h as originalH,
ref,
render,
+ serialize,
serializeInner,
withDirectives,
} from '@vue/runtime-test'
-import { Fragment, createCommentVNode, createVNode } from '../../src/vnode'
+import {
+ Fragment,
+ createBlock,
+ createCommentVNode,
+ createTextVNode,
+ createVNode,
+ openBlock,
+} from '../../src/vnode'
+import { toDisplayString } from '@vue/shared'
import { compile, createApp as createDOMApp, render as domRender } from 'vue'
describe('renderer: teleport', () => {
@@ -243,6 +252,39 @@ describe('renderer: teleport', () => {
expect(serializeInner(target)).toBe(`teleported`)
})
+ test('should traverse comment node after updating in optimize mode', async () => {
+ const target = nodeOps.createElement('div')
+ const root = nodeOps.createElement('div')
+ const count = ref(0)
+ let teleport
+
+ __DEV__ = false
+ render(
+ h(() => {
+ teleport =
+ (openBlock(),
+ createBlock(Teleport, { to: target }, [
+ createCommentVNode('comment in teleport'),
+ ]))
+ return h('div', null, [
+ createTextVNode(toDisplayString(count.value)),
+ teleport,
+ ])
+ }),
+ root,
+ )
+ const commentNode = teleport!.children[0].el
+ expect(serializeInner(root)).toBe(`
0
`)
+ expect(serializeInner(target)).toBe(``)
+ expect(serialize(commentNode)).toBe(``)
+
+ count.value = 1
+ await nextTick()
+ __DEV__ = true
+ expect(serializeInner(root)).toBe(`1
`)
+ expect(teleport!.children[0].el).toBe(commentNode)
+ })
+
test('should remove children when unmounted', () => {
const target = nodeOps.createElement('div')
const root = nodeOps.createElement('div')
@@ -269,6 +311,34 @@ describe('renderer: teleport', () => {
testUnmount({ to: null, disabled: true })
})
+ // #10747
+ test('should unmount correctly when using top level comment in teleport', async () => {
+ const target = nodeOps.createElement('div')
+ const root = nodeOps.createElement('div')
+ const count = ref(0)
+
+ __DEV__ = false
+ render(
+ h(() => {
+ return h('div', null, [
+ createTextVNode(toDisplayString(count.value)),
+ (openBlock(),
+ createBlock(Teleport, { to: target }, [
+ createCommentVNode('comment in teleport'),
+ ])),
+ ])
+ }),
+ root,
+ )
+
+ count.value = 1
+
+ await nextTick()
+ __DEV__ = true
+ render(null, root)
+ expect(root.children.length).toBe(0)
+ })
+
test('component with multi roots should be removed when unmounted', () => {
const target = nodeOps.createElement('div')
const root = nodeOps.createElement('div')
diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts
index 90cc22f5470..a60cb9fbf05 100644
--- a/packages/runtime-core/src/renderer.ts
+++ b/packages/runtime-core/src/renderer.ts
@@ -2480,7 +2480,7 @@ export function traverseStaticChildren(
}
// also inherit for comment nodes, but not placeholders (e.g. v-if which
// would have received .el during block patch)
- if (__DEV__ && c2.type === Comment && !c2.el) {
+ if (c2.type === Comment && !c2.el) {
c2.el = c1.el
}
}