refactor: cache constant check result on transform context
also fix edge case for missed createVNode import on static svg nodes
This commit is contained in:
parent
ad4d3915d3
commit
a8352506f6
@ -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(
|
||||
@ -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),
|
||||
|
@ -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<TemplateChildNode, ConstantTypes>,
|
||||
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<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
|
||||
}
|
||||
@ -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<TemplateChildNode, ConstantTypes>
|
||||
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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 +
|
||||
|
Loading…
Reference in New Issue
Block a user