Skip to content

Commit

Permalink
refactor: cache constant check result on transform context
Browse files Browse the repository at this point in the history
also fix edge case for missed createVNode import on static svg nodes
  • Loading branch information
yyx990803 committed Dec 3, 2020
1 parent ad4d391 commit a835250
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 29 deletions.
2 changes: 2 additions & 0 deletions packages/compiler-core/src/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ export interface TransformContext
removeIdentifiers(exp: ExpressionNode | string): void
hoist(exp: JSChildNode): SimpleExpressionNode
cache<T extends JSChildNode>(exp: T, isVNode?: boolean): CacheExpression | T
constantCache: Map<TemplateChildNode, ConstantTypes>
}

export function createTransformContext(
Expand Down Expand Up @@ -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),
Expand Down
49 changes: 23 additions & 26 deletions packages/compiler-core/src/transforms/hoistStatic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand All @@ -41,7 +41,6 @@ export function isSingleElementRoot(
function walk(
node: ParentNode,
context: TransformContext,
resultCache: Map<TemplateChildNode, ConstantTypes>,
doNotHoistNode: boolean = false
) {
let hasHoistedNode = false
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -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
)
}
Expand All @@ -136,14 +134,15 @@ function walk(

export function getConstantType(
node: TemplateChildNode | SimpleExpressionNode,
resultCache: Map<TemplateChildNode, ConstantTypes> = 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
}
Expand All @@ -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) {
Expand All @@ -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) {
Expand All @@ -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) {
Expand All @@ -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:
Expand All @@ -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:
Expand All @@ -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) {
Expand All @@ -256,15 +253,15 @@ export function getConstantType(

function getGeneratedPropsConstantType(
node: PlainElementNode,
resultCache: Map<TemplateChildNode, ConstantTypes>
context: TransformContext
): ConstantTypes {
let returnType = ConstantTypes.CAN_STRINGIFY
const props = getNodeProps(node)
if (props && props.type === NodeTypes.JS_OBJECT_EXPRESSION) {
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
}
Expand All @@ -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
}
Expand Down
4 changes: 2 additions & 2 deletions packages/compiler-core/src/transforms/transformElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion packages/compiler-core/src/transforms/transformText.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 +
Expand Down

0 comments on commit a835250

Please sign in to comment.