From a8352506f6ee7fee784c47d2a6907071215602fc Mon Sep 17 00:00:00 2001 From: Evan You Date: Thu, 3 Dec 2020 11:10:40 -0500 Subject: [PATCH] refactor: cache constant check result on transform context also fix edge case for missed createVNode import on static svg nodes --- packages/compiler-core/src/transform.ts | 2 + .../src/transforms/hoistStatic.ts | 49 +++++++++---------- .../src/transforms/transformElement.ts | 4 +- .../src/transforms/transformText.ts | 2 +- 4 files changed, 28 insertions(+), 29 deletions(-) diff --git a/packages/compiler-core/src/transform.ts b/packages/compiler-core/src/transform.ts index 474f491595c..2a23efcb52e 100644 --- a/packages/compiler-core/src/transform.ts +++ b/packages/compiler-core/src/transform.ts @@ -111,6 +111,7 @@ export interface TransformContext removeIdentifiers(exp: ExpressionNode | string): void hoist(exp: JSChildNode): SimpleExpressionNode cache(exp: T, isVNode?: boolean): CacheExpression | T + constantCache: Map } export function createTransformContext( @@ -163,6 +164,7 @@ export function createTransformContext( directives: new Set(), hoists: [], imports: new Set(), + constantCache: new Map(), temps: 0, cached: 0, identifiers: Object.create(null), diff --git a/packages/compiler-core/src/transforms/hoistStatic.ts b/packages/compiler-core/src/transforms/hoistStatic.ts index 1c066d7b8eb..004a1e5a116 100644 --- a/packages/compiler-core/src/transforms/hoistStatic.ts +++ b/packages/compiler-core/src/transforms/hoistStatic.ts @@ -14,12 +14,12 @@ import { import { TransformContext } from '../transform' import { PatchFlags, isString, isSymbol } from '@vue/shared' import { isSlotOutlet } from '../utils' +import { CREATE_VNODE } from '../runtimeHelpers' export function hoistStatic(root: RootNode, context: TransformContext) { walk( root, context, - new Map(), // Root node is unfortunately non-hoistable due to potential parent // fallthrough attributes. isSingleElementRoot(root, root.children[0]) @@ -41,7 +41,6 @@ export function isSingleElementRoot( function walk( node: ParentNode, context: TransformContext, - resultCache: Map, doNotHoistNode: boolean = false ) { let hasHoistedNode = false @@ -65,7 +64,7 @@ function walk( ) { const constantType = doNotHoistNode ? ConstantTypes.NOT_CONSTANT - : getConstantType(child, resultCache) + : getConstantType(child, context) if (constantType > ConstantTypes.NOT_CONSTANT) { if (constantType < ConstantTypes.CAN_STRINGIFY) { canStringify = false @@ -87,7 +86,7 @@ function walk( (!flag || flag === PatchFlags.NEED_PATCH || flag === PatchFlags.TEXT) && - getGeneratedPropsConstantType(child, resultCache) >= + getGeneratedPropsConstantType(child, context) >= ConstantTypes.CAN_HOIST ) { const props = getNodeProps(child) @@ -98,7 +97,7 @@ function walk( } } } else if (child.type === NodeTypes.TEXT_CALL) { - const contentType = getConstantType(child.content, resultCache) + const contentType = getConstantType(child.content, context) if (contentType > 0) { if (contentType < ConstantTypes.CAN_STRINGIFY) { canStringify = false @@ -112,17 +111,16 @@ function walk( // walk further if (child.type === NodeTypes.ELEMENT) { - walk(child, context, resultCache) + walk(child, context) } else if (child.type === NodeTypes.FOR) { // Do not hoist v-for single child because it has to be a block - walk(child, context, resultCache, child.children.length === 1) + walk(child, context, child.children.length === 1) } else if (child.type === NodeTypes.IF) { for (let i = 0; i < child.branches.length; i++) { // Do not hoist v-if single child because it has to be a block walk( child.branches[i], context, - resultCache, child.branches[i].children.length === 1 ) } @@ -136,14 +134,15 @@ function walk( export function getConstantType( node: TemplateChildNode | SimpleExpressionNode, - resultCache: Map = new Map() + context: TransformContext ): ConstantTypes { + const { constantCache } = context switch (node.type) { case NodeTypes.ELEMENT: if (node.tagType !== ElementTypes.ELEMENT) { return ConstantTypes.NOT_CONSTANT } - const cached = resultCache.get(node) + const cached = constantCache.get(node) if (cached !== undefined) { return cached } @@ -161,12 +160,9 @@ export function getConstantType( // non-hoistable expressions that refers to scope variables, e.g. compiler // injected keys or cached event handlers. Therefore we need to always // check the codegenNode's props to be sure. - const generatedPropsType = getGeneratedPropsConstantType( - node, - resultCache - ) + const generatedPropsType = getGeneratedPropsConstantType(node, context) if (generatedPropsType === ConstantTypes.NOT_CONSTANT) { - resultCache.set(node, ConstantTypes.NOT_CONSTANT) + constantCache.set(node, ConstantTypes.NOT_CONSTANT) return ConstantTypes.NOT_CONSTANT } if (generatedPropsType < returnType) { @@ -175,9 +171,9 @@ export function getConstantType( // 2. its children. for (let i = 0; i < node.children.length; i++) { - const childType = getConstantType(node.children[i], resultCache) + const childType = getConstantType(node.children[i], context) if (childType === ConstantTypes.NOT_CONSTANT) { - resultCache.set(node, ConstantTypes.NOT_CONSTANT) + constantCache.set(node, ConstantTypes.NOT_CONSTANT) return ConstantTypes.NOT_CONSTANT } if (childType < returnType) { @@ -193,9 +189,9 @@ export function getConstantType( for (let i = 0; i < node.props.length; i++) { const p = node.props[i] if (p.type === NodeTypes.DIRECTIVE && p.name === 'bind' && p.exp) { - const expType = getConstantType(p.exp, resultCache) + const expType = getConstantType(p.exp, context) if (expType === ConstantTypes.NOT_CONSTANT) { - resultCache.set(node, ConstantTypes.NOT_CONSTANT) + constantCache.set(node, ConstantTypes.NOT_CONSTANT) return ConstantTypes.NOT_CONSTANT } if (expType < returnType) { @@ -210,12 +206,13 @@ export function getConstantType( // nested updates. if (codegenNode.isBlock) { codegenNode.isBlock = false + context.helper(CREATE_VNODE) } - resultCache.set(node, returnType) + constantCache.set(node, returnType) return returnType } else { - resultCache.set(node, ConstantTypes.NOT_CONSTANT) + constantCache.set(node, ConstantTypes.NOT_CONSTANT) return ConstantTypes.NOT_CONSTANT } case NodeTypes.TEXT: @@ -227,7 +224,7 @@ export function getConstantType( return ConstantTypes.NOT_CONSTANT case NodeTypes.INTERPOLATION: case NodeTypes.TEXT_CALL: - return getConstantType(node.content, resultCache) + return getConstantType(node.content, context) case NodeTypes.SIMPLE_EXPRESSION: return node.constType case NodeTypes.COMPOUND_EXPRESSION: @@ -237,7 +234,7 @@ export function getConstantType( if (isString(child) || isSymbol(child)) { continue } - const childType = getConstantType(child, resultCache) + const childType = getConstantType(child, context) if (childType === ConstantTypes.NOT_CONSTANT) { return ConstantTypes.NOT_CONSTANT } else if (childType < returnType) { @@ -256,7 +253,7 @@ export function getConstantType( function getGeneratedPropsConstantType( node: PlainElementNode, - resultCache: Map + context: TransformContext ): ConstantTypes { let returnType = ConstantTypes.CAN_STRINGIFY const props = getNodeProps(node) @@ -264,7 +261,7 @@ function getGeneratedPropsConstantType( const { properties } = props for (let i = 0; i < properties.length; i++) { const { key, value } = properties[i] - const keyType = getConstantType(key, resultCache) + const keyType = getConstantType(key, context) if (keyType === ConstantTypes.NOT_CONSTANT) { return keyType } @@ -274,7 +271,7 @@ function getGeneratedPropsConstantType( if (value.type !== NodeTypes.SIMPLE_EXPRESSION) { return ConstantTypes.NOT_CONSTANT } - const valueType = getConstantType(value, resultCache) + const valueType = getConstantType(value, context) if (valueType === ConstantTypes.NOT_CONSTANT) { return valueType } diff --git a/packages/compiler-core/src/transforms/transformElement.ts b/packages/compiler-core/src/transforms/transformElement.ts index 53b148b42bb..0283d3eec5e 100644 --- a/packages/compiler-core/src/transforms/transformElement.ts +++ b/packages/compiler-core/src/transforms/transformElement.ts @@ -168,7 +168,7 @@ export const transformElement: NodeTransform = (node, context) => { type === NodeTypes.COMPOUND_EXPRESSION if ( hasDynamicTextChild && - getConstantType(child) === ConstantTypes.NOT_CONSTANT + getConstantType(child, context) === ConstantTypes.NOT_CONSTANT ) { patchFlag |= PatchFlags.TEXT } @@ -373,7 +373,7 @@ export function buildProps( value.type === NodeTypes.JS_CACHE_EXPRESSION || ((value.type === NodeTypes.SIMPLE_EXPRESSION || value.type === NodeTypes.COMPOUND_EXPRESSION) && - getConstantType(value) > 0) + getConstantType(value, context) > 0) ) { // skip if the prop is a cached handler or has constant value return diff --git a/packages/compiler-core/src/transforms/transformText.ts b/packages/compiler-core/src/transforms/transformText.ts index 0c672f9cc8c..3576e0e2cbf 100644 --- a/packages/compiler-core/src/transforms/transformText.ts +++ b/packages/compiler-core/src/transforms/transformText.ts @@ -82,7 +82,7 @@ export const transformText: NodeTransform = (node, context) => { // mark dynamic text with flag so it gets patched inside a block if ( !context.ssr && - getConstantType(child) === ConstantTypes.NOT_CONSTANT + getConstantType(child, context) === ConstantTypes.NOT_CONSTANT ) { callArgs.push( PatchFlags.TEXT +