fix(compiler-core): bail out to array children when the element has custom directives + only one text child node (#3757)

This commit is contained in:
HcySunYang 2021-05-13 04:12:32 +08:00 committed by GitHub
parent 0e3bbd0626
commit a56ab148fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 3 deletions

View 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`] = ` exports[`compiler: transform text no consecutive text 1`] = `
"const _Vue = Vue "const _Vue = Vue

View File

@ -4,7 +4,8 @@ import {
transform, transform,
NodeTypes, NodeTypes,
generate, generate,
ForNode ForNode,
ElementNode
} from '../../src' } from '../../src'
import { transformFor } from '../../src/transforms/vFor' import { transformFor } from '../../src/transforms/vFor'
import { transformText } from '../../src/transforms/transformText' import { transformText } from '../../src/transforms/transformText'
@ -20,8 +21,8 @@ function transformWithTextOpt(template: string, options: CompilerOptions = {}) {
nodeTransforms: [ nodeTransforms: [
transformFor, transformFor,
...(options.prefixIdentifiers ? [transformExpression] : []), ...(options.prefixIdentifiers ? [transformExpression] : []),
transformText, transformElement,
transformElement transformText
], ],
...options ...options
}) })
@ -193,4 +194,29 @@ describe('compiler: transform text', () => {
}).code }).code
).toMatchSnapshot() ).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()
})
}) })

View File

@ -64,6 +64,16 @@ export const transformText: NodeTransform = (node, context) => {
(node.type === NodeTypes.ROOT || (node.type === NodeTypes.ROOT ||
(node.type === NodeTypes.ELEMENT && (node.type === NodeTypes.ELEMENT &&
node.tagType === ElementTypes.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 // in compat mode, <template> tags with no special directives
// will be rendered as a fragment so its children must be // will be rendered as a fragment so its children must be
// converted into vnodes. // converted into vnodes.