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])
function walk(
node: ParentNode,
context: TransformContext,
- resultCache: Map<TemplateChildNode, ConstantTypes>,
doNotHoistNode: boolean = false
) {
let hasHoistedNode = false
) {
const constantType = doNotHoistNode
? ConstantTypes.NOT_CONSTANT
- : getConstantType(child, resultCache)
+ : getConstantType(child, context)
if (constantType > ConstantTypes.NOT_CONSTANT) {
if (constantType < ConstantTypes.CAN_STRINGIFY) {
canStringify = false
(!flag ||
flag === PatchFlags.NEED_PATCH ||
flag === PatchFlags.TEXT) &&
- getGeneratedPropsConstantType(child, resultCache) >=
+ getGeneratedPropsConstantType(child, context) >=
ConstantTypes.CAN_HOIST
) {
const props = getNodeProps(child)
}
}
} 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
// 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
)
}
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
}
// 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) {
// 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) {
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) {
// 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:
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:
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) {
function getGeneratedPropsConstantType(
node: PlainElementNode,
- resultCache: Map<TemplateChildNode, ConstantTypes>
+ context: TransformContext
): ConstantTypes {
let returnType = ConstantTypes.CAN_STRINGIFY
const props = getNodeProps(node)
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
}
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
}