Skip to content

Commit a56ab14

Browse files
authored
fix(compiler-core): bail out to array children when the element has custom directives + only one text child node (#3757)
1 parent 0e3bbd0 commit a56ab14

File tree

3 files changed

+57
-3
lines changed

3 files changed

+57
-3
lines changed

packages/compiler-core/__tests__/transforms/__snapshots__/transformText.spec.ts.snap

+18
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,24 @@ return function render(_ctx, _cache) {
6262
}"
6363
`;
6464
65+
exports[`compiler: transform text element with custom directives and only one text child node 1`] = `
66+
"const _Vue = Vue
67+
68+
return function render(_ctx, _cache) {
69+
with (_ctx) {
70+
const { toDisplayString: _toDisplayString, createTextVNode: _createTextVNode, resolveDirective: _resolveDirective, withDirectives: _withDirectives, openBlock: _openBlock, createBlock: _createBlock } = _Vue
71+
72+
const _directive_foo = _resolveDirective(\\"foo\\")
73+
74+
return _withDirectives((_openBlock(), _createBlock(\\"p\\", null, [
75+
_createTextVNode(_toDisplayString(foo), 1 /* TEXT */)
76+
], 512 /* NEED_PATCH */)), [
77+
[_directive_foo]
78+
])
79+
}
80+
}"
81+
`;
82+
6583
exports[`compiler: transform text no consecutive text 1`] = `
6684
"const _Vue = Vue
6785

packages/compiler-core/__tests__/transforms/transformText.spec.ts

+29-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import {
44
transform,
55
NodeTypes,
66
generate,
7-
ForNode
7+
ForNode,
8+
ElementNode
89
} from '../../src'
910
import { transformFor } from '../../src/transforms/vFor'
1011
import { transformText } from '../../src/transforms/transformText'
@@ -20,8 +21,8 @@ function transformWithTextOpt(template: string, options: CompilerOptions = {}) {
2021
nodeTransforms: [
2122
transformFor,
2223
...(options.prefixIdentifiers ? [transformExpression] : []),
23-
transformText,
24-
transformElement
24+
transformElement,
25+
transformText
2526
],
2627
...options
2728
})
@@ -193,4 +194,29 @@ describe('compiler: transform text', () => {
193194
}).code
194195
).toMatchSnapshot()
195196
})
197+
198+
// #3756
199+
test('element with custom directives and only one text child node', () => {
200+
const root = transformWithTextOpt(`<p v-foo>{{ foo }}</p>`)
201+
expect(root.children.length).toBe(1)
202+
expect(root.children[0].type).toBe(NodeTypes.ELEMENT)
203+
expect((root.children[0] as ElementNode).children[0]).toMatchObject({
204+
type: NodeTypes.TEXT_CALL,
205+
codegenNode: {
206+
type: NodeTypes.JS_CALL_EXPRESSION,
207+
callee: CREATE_TEXT,
208+
arguments: [
209+
{
210+
type: NodeTypes.INTERPOLATION,
211+
content: {
212+
type: NodeTypes.SIMPLE_EXPRESSION,
213+
content: 'foo'
214+
}
215+
},
216+
genFlagText(PatchFlags.TEXT)
217+
]
218+
}
219+
})
220+
expect(generate(root).code).toMatchSnapshot()
221+
})
196222
})

packages/compiler-core/src/transforms/transformText.ts

+10
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,16 @@ export const transformText: NodeTransform = (node, context) => {
6464
(node.type === NodeTypes.ROOT ||
6565
(node.type === NodeTypes.ELEMENT &&
6666
node.tagType === ElementTypes.ELEMENT &&
67+
// #3756
68+
// custom directives can potentially add DOM elements arbitrarily,
69+
// we need to avoid setting textContent of the element at runtime
70+
// to avoid accidentally overwriting the DOM elements added
71+
// by the user through custom directives.
72+
!node.props.find(
73+
p =>
74+
p.type === NodeTypes.DIRECTIVE &&
75+
!context.directiveTransforms[p.name]
76+
) &&
6777
// in compat mode, <template> tags with no special directives
6878
// will be rendered as a fragment so its children must be
6979
// converted into vnodes.

0 commit comments

Comments
 (0)