From 42f3f9e832022156537e7ce9ae1eb6d057baaec8 Mon Sep 17 00:00:00 2001 From: Evan You Date: Mon, 2 Dec 2019 15:17:00 -0500 Subject: [PATCH] fix(compiler-core): should pre-convert text nodes in all non-element cases --- .../src/transforms/transformText.ts | 67 +++++++++++-------- 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/packages/compiler-core/src/transforms/transformText.ts b/packages/compiler-core/src/transforms/transformText.ts index 25bf22d4..91d5d507 100644 --- a/packages/compiler-core/src/transforms/transformText.ts +++ b/packages/compiler-core/src/transforms/transformText.ts @@ -6,7 +6,8 @@ import { InterpolationNode, CompoundExpressionNode, createCallExpression, - CallExpression + CallExpression, + ElementTypes } from '../ast' import { CREATE_TEXT } from '../runtimeHelpers' import { PatchFlags, PatchFlagNames } from '@vue/shared' @@ -53,33 +54,43 @@ export const transformText: NodeTransform = (node, context) => { } } - if (hasText && children.length > 1) { - // when an element has mixed text/element children, convert text nodes - // into createTextVNode(text) calls. - for (let i = 0; i < children.length; i++) { - const child = children[i] - if (isText(child) || child.type === NodeTypes.COMPOUND_EXPRESSION) { - const callArgs: CallExpression['arguments'] = [] - // createTextVNode defaults to single whitespace, so if it is a - // single space the code could be an empty call to save bytes. - if (child.type !== NodeTypes.TEXT || child.content !== ' ') { - callArgs.push(child) - } - // mark dynamic text with flag so it gets patched inside a block - if (child.type !== NodeTypes.TEXT) { - callArgs.push( - `${PatchFlags.TEXT} /* ${PatchFlagNames[PatchFlags.TEXT]} */` - ) - } - children[i] = { - type: NodeTypes.TEXT_CALL, - content: child, - loc: child.loc, - codegenNode: createCallExpression( - context.helper(CREATE_TEXT), - callArgs - ) - } + if ( + !hasText || + // if this is a plain element with a single text child, leave it as-is + // since the runtime has dedicated fast path for this by directly + // setting textContent of the element. + (node.type === NodeTypes.ELEMENT && + node.tagType === ElementTypes.ELEMENT && + children.length === 1) + ) { + return + } + + // pre-convert text nodes into createTextVNode(text) calls to avoid + // runtime normalization. + for (let i = 0; i < children.length; i++) { + const child = children[i] + if (isText(child) || child.type === NodeTypes.COMPOUND_EXPRESSION) { + const callArgs: CallExpression['arguments'] = [] + // createTextVNode defaults to single whitespace, so if it is a + // single space the code could be an empty call to save bytes. + if (child.type !== NodeTypes.TEXT || child.content !== ' ') { + callArgs.push(child) + } + // mark dynamic text with flag so it gets patched inside a block + if (child.type !== NodeTypes.TEXT) { + callArgs.push( + `${PatchFlags.TEXT} /* ${PatchFlagNames[PatchFlags.TEXT]} */` + ) + } + children[i] = { + type: NodeTypes.TEXT_CALL, + content: child, + loc: child.loc, + codegenNode: createCallExpression( + context.helper(CREATE_TEXT), + callArgs + ) } } }