Просмотр исходного кода

fix(runtime-core): inherit comment nodes during block patch in production build (#10748)

close #10747
close #12650
tonicli 11 месяцев назад
Родитель
Сommit
626450590d

+ 71 - 1
packages/runtime-core/__tests__/components/Teleport.spec.ts

@@ -14,10 +14,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'
 import type { HMRRuntime } from '../../src/hmr'
 
@@ -248,6 +257,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(`<div>0</div>`)
+      expect(serializeInner(target)).toBe(`<!--comment in teleport-->`)
+      expect(serialize(commentNode)).toBe(`<!--comment in teleport-->`)
+
+      count.value = 1
+      await nextTick()
+      __DEV__ = true
+      expect(serializeInner(root)).toBe(`<div>1</div>`)
+      expect(teleport!.children[0].el).toBe(commentNode)
+    })
+
     test('should remove children when unmounted', () => {
       const target = nodeOps.createElement('div')
       const root = nodeOps.createElement('div')
@@ -274,6 +316,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')

+ 6 - 6
packages/runtime-core/src/renderer.ts

@@ -2503,13 +2503,13 @@ export function traverseStaticChildren(
       if (c2.type === Text) {
         c2.el = c1.el
       }
-      if (__DEV__) {
-        // #2324 also inherit for comment nodes, but not placeholders (e.g. v-if which
-        // would have received .el during block patch)
-        if (c2.type === Comment && !c2.el) {
-          c2.el = c1.el
-        }
+      // #2324 also inherit for comment nodes, but not placeholders (e.g. v-if which
+      // would have received .el during block patch)
+      if (c2.type === Comment && !c2.el) {
+        c2.el = c1.el
+      }
 
+      if (__DEV__) {
         c2.el && (c2.el.__vnode = c2)
       }
     }