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 } }