]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler-core): bail out to array children when the element has custom directives...
authorHcySunYang <HcySunYang@outlook.com>
Wed, 12 May 2021 20:12:32 +0000 (04:12 +0800)
committerGitHub <noreply@github.com>
Wed, 12 May 2021 20:12:32 +0000 (16:12 -0400)
packages/compiler-core/__tests__/transforms/__snapshots__/transformText.spec.ts.snap
packages/compiler-core/__tests__/transforms/transformText.spec.ts
packages/compiler-core/src/transforms/transformText.ts

index b626c6e9ae23b387a59b5043c83f258992c954c1..07dadbcdc6450a868615e2dfc7f3e4499a5bdbf6 100644 (file)
@@ -62,6 +62,24 @@ return function render(_ctx, _cache) {
 }"
 `;
 
+exports[`compiler: transform text element with custom directives and only one text child node 1`] = `
+"const _Vue = Vue
+
+return function render(_ctx, _cache) {
+  with (_ctx) {
+    const { toDisplayString: _toDisplayString, createTextVNode: _createTextVNode, resolveDirective: _resolveDirective, withDirectives: _withDirectives, openBlock: _openBlock, createBlock: _createBlock } = _Vue
+
+    const _directive_foo = _resolveDirective(\\"foo\\")
+
+    return _withDirectives((_openBlock(), _createBlock(\\"p\\", null, [
+      _createTextVNode(_toDisplayString(foo), 1 /* TEXT */)
+    ], 512 /* NEED_PATCH */)), [
+      [_directive_foo]
+    ])
+  }
+}"
+`;
+
 exports[`compiler: transform text no consecutive text 1`] = `
 "const _Vue = Vue
 
index ab5341c32be0a85b6f1031fccada9d2eed5a422c..6e321d145e5bd156f799cdc62ca57a39e9a80726 100644 (file)
@@ -4,7 +4,8 @@ import {
   transform,
   NodeTypes,
   generate,
-  ForNode
+  ForNode,
+  ElementNode
 } from '../../src'
 import { transformFor } from '../../src/transforms/vFor'
 import { transformText } from '../../src/transforms/transformText'
@@ -20,8 +21,8 @@ function transformWithTextOpt(template: string, options: CompilerOptions = {}) {
     nodeTransforms: [
       transformFor,
       ...(options.prefixIdentifiers ? [transformExpression] : []),
-      transformText,
-      transformElement
+      transformElement,
+      transformText
     ],
     ...options
   })
@@ -193,4 +194,29 @@ describe('compiler: transform text', () => {
       }).code
     ).toMatchSnapshot()
   })
+
+  // #3756
+  test('element with custom directives and only one text child node', () => {
+    const root = transformWithTextOpt(`<p v-foo>{{ foo }}</p>`)
+    expect(root.children.length).toBe(1)
+    expect(root.children[0].type).toBe(NodeTypes.ELEMENT)
+    expect((root.children[0] as ElementNode).children[0]).toMatchObject({
+      type: NodeTypes.TEXT_CALL,
+      codegenNode: {
+        type: NodeTypes.JS_CALL_EXPRESSION,
+        callee: CREATE_TEXT,
+        arguments: [
+          {
+            type: NodeTypes.INTERPOLATION,
+            content: {
+              type: NodeTypes.SIMPLE_EXPRESSION,
+              content: 'foo'
+            }
+          },
+          genFlagText(PatchFlags.TEXT)
+        ]
+      }
+    })
+    expect(generate(root).code).toMatchSnapshot()
+  })
 })
index a8b65c966a830c3e358adc367e8e4a9e9e6e0e53..2ab6805c6a7b6e15e82d1e5fa4eafe31438b2766 100644 (file)
@@ -64,6 +64,16 @@ export const transformText: NodeTransform = (node, context) => {
           (node.type === NodeTypes.ROOT ||
             (node.type === NodeTypes.ELEMENT &&
               node.tagType === ElementTypes.ELEMENT &&
+              // #3756
+              // custom directives can potentially add DOM elements arbitrarily,
+              // we need to avoid setting textContent of the element at runtime
+              // to avoid accidentally overwriting the DOM elements added
+              // by the user through custom directives.
+              !node.props.find(
+                p =>
+                  p.type === NodeTypes.DIRECTIVE &&
+                  !context.directiveTransforms[p.name]
+              ) &&
               // in compat mode, <template> tags with no special directives
               // will be rendered as a fragment so its children must be
               // converted into vnodes.