Skip to content

Commit a835250

Browse files
committed
refactor: cache constant check result on transform context
also fix edge case for missed createVNode import on static svg nodes
1 parent ad4d391 commit a835250

File tree

4 files changed

+28
-29
lines changed

4 files changed

+28
-29
lines changed

packages/compiler-core/src/transform.ts

+2
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ export interface TransformContext
111111
removeIdentifiers(exp: ExpressionNode | string): void
112112
hoist(exp: JSChildNode): SimpleExpressionNode
113113
cache<T extends JSChildNode>(exp: T, isVNode?: boolean): CacheExpression | T
114+
constantCache: Map<TemplateChildNode, ConstantTypes>
114115
}
115116

116117
export function createTransformContext(
@@ -163,6 +164,7 @@ export function createTransformContext(
163164
directives: new Set(),
164165
hoists: [],
165166
imports: new Set(),
167+
constantCache: new Map(),
166168
temps: 0,
167169
cached: 0,
168170
identifiers: Object.create(null),

packages/compiler-core/src/transforms/hoistStatic.ts

+23-26
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ import {
1414
import { TransformContext } from '../transform'
1515
import { PatchFlags, isString, isSymbol } from '@vue/shared'
1616
import { isSlotOutlet } from '../utils'
17+
import { CREATE_VNODE } from '../runtimeHelpers'
1718

1819
export function hoistStatic(root: RootNode, context: TransformContext) {
1920
walk(
2021
root,
2122
context,
22-
new Map(),
2323
// Root node is unfortunately non-hoistable due to potential parent
2424
// fallthrough attributes.
2525
isSingleElementRoot(root, root.children[0])
@@ -41,7 +41,6 @@ export function isSingleElementRoot(
4141
function walk(
4242
node: ParentNode,
4343
context: TransformContext,
44-
resultCache: Map<TemplateChildNode, ConstantTypes>,
4544
doNotHoistNode: boolean = false
4645
) {
4746
let hasHoistedNode = false
@@ -65,7 +64,7 @@ function walk(
6564
) {
6665
const constantType = doNotHoistNode
6766
? ConstantTypes.NOT_CONSTANT
68-
: getConstantType(child, resultCache)
67+
: getConstantType(child, context)
6968
if (constantType > ConstantTypes.NOT_CONSTANT) {
7069
if (constantType < ConstantTypes.CAN_STRINGIFY) {
7170
canStringify = false
@@ -87,7 +86,7 @@ function walk(
8786
(!flag ||
8887
flag === PatchFlags.NEED_PATCH ||
8988
flag === PatchFlags.TEXT) &&
90-
getGeneratedPropsConstantType(child, resultCache) >=
89+
getGeneratedPropsConstantType(child, context) >=
9190
ConstantTypes.CAN_HOIST
9291
) {
9392
const props = getNodeProps(child)
@@ -98,7 +97,7 @@ function walk(
9897
}
9998
}
10099
} else if (child.type === NodeTypes.TEXT_CALL) {
101-
const contentType = getConstantType(child.content, resultCache)
100+
const contentType = getConstantType(child.content, context)
102101
if (contentType > 0) {
103102
if (contentType < ConstantTypes.CAN_STRINGIFY) {
104103
canStringify = false
@@ -112,17 +111,16 @@ function walk(
112111

113112
// walk further
114113
if (child.type === NodeTypes.ELEMENT) {
115-
walk(child, context, resultCache)
114+
walk(child, context)
116115
} else if (child.type === NodeTypes.FOR) {
117116
// Do not hoist v-for single child because it has to be a block
118-
walk(child, context, resultCache, child.children.length === 1)
117+
walk(child, context, child.children.length === 1)
119118
} else if (child.type === NodeTypes.IF) {
120119
for (let i = 0; i < child.branches.length; i++) {
121120
// Do not hoist v-if single child because it has to be a block
122121
walk(
123122
child.branches[i],
124123
context,
125-
resultCache,
126124
child.branches[i].children.length === 1
127125
)
128126
}
@@ -136,14 +134,15 @@ function walk(
136134

137135
export function getConstantType(
138136
node: TemplateChildNode | SimpleExpressionNode,
139-
resultCache: Map<TemplateChildNode, ConstantTypes> = new Map()
137+
context: TransformContext
140138
): ConstantTypes {
139+
const { constantCache } = context
141140
switch (node.type) {
142141
case NodeTypes.ELEMENT:
143142
if (node.tagType !== ElementTypes.ELEMENT) {
144143
return ConstantTypes.NOT_CONSTANT
145144
}
146-
const cached = resultCache.get(node)
145+
const cached = constantCache.get(node)
147146
if (cached !== undefined) {
148147
return cached
149148
}
@@ -161,12 +160,9 @@ export function getConstantType(
161160
// non-hoistable expressions that refers to scope variables, e.g. compiler
162161
// injected keys or cached event handlers. Therefore we need to always
163162
// check the codegenNode's props to be sure.
164-
const generatedPropsType = getGeneratedPropsConstantType(
165-
node,
166-
resultCache
167-
)
163+
const generatedPropsType = getGeneratedPropsConstantType(node, context)
168164
if (generatedPropsType === ConstantTypes.NOT_CONSTANT) {
169-
resultCache.set(node, ConstantTypes.NOT_CONSTANT)
165+
constantCache.set(node, ConstantTypes.NOT_CONSTANT)
170166
return ConstantTypes.NOT_CONSTANT
171167
}
172168
if (generatedPropsType < returnType) {
@@ -175,9 +171,9 @@ export function getConstantType(
175171

176172
// 2. its children.
177173
for (let i = 0; i < node.children.length; i++) {
178-
const childType = getConstantType(node.children[i], resultCache)
174+
const childType = getConstantType(node.children[i], context)
179175
if (childType === ConstantTypes.NOT_CONSTANT) {
180-
resultCache.set(node, ConstantTypes.NOT_CONSTANT)
176+
constantCache.set(node, ConstantTypes.NOT_CONSTANT)
181177
return ConstantTypes.NOT_CONSTANT
182178
}
183179
if (childType < returnType) {
@@ -193,9 +189,9 @@ export function getConstantType(
193189
for (let i = 0; i < node.props.length; i++) {
194190
const p = node.props[i]
195191
if (p.type === NodeTypes.DIRECTIVE && p.name === 'bind' && p.exp) {
196-
const expType = getConstantType(p.exp, resultCache)
192+
const expType = getConstantType(p.exp, context)
197193
if (expType === ConstantTypes.NOT_CONSTANT) {
198-
resultCache.set(node, ConstantTypes.NOT_CONSTANT)
194+
constantCache.set(node, ConstantTypes.NOT_CONSTANT)
199195
return ConstantTypes.NOT_CONSTANT
200196
}
201197
if (expType < returnType) {
@@ -210,12 +206,13 @@ export function getConstantType(
210206
// nested updates.
211207
if (codegenNode.isBlock) {
212208
codegenNode.isBlock = false
209+
context.helper(CREATE_VNODE)
213210
}
214211

215-
resultCache.set(node, returnType)
212+
constantCache.set(node, returnType)
216213
return returnType
217214
} else {
218-
resultCache.set(node, ConstantTypes.NOT_CONSTANT)
215+
constantCache.set(node, ConstantTypes.NOT_CONSTANT)
219216
return ConstantTypes.NOT_CONSTANT
220217
}
221218
case NodeTypes.TEXT:
@@ -227,7 +224,7 @@ export function getConstantType(
227224
return ConstantTypes.NOT_CONSTANT
228225
case NodeTypes.INTERPOLATION:
229226
case NodeTypes.TEXT_CALL:
230-
return getConstantType(node.content, resultCache)
227+
return getConstantType(node.content, context)
231228
case NodeTypes.SIMPLE_EXPRESSION:
232229
return node.constType
233230
case NodeTypes.COMPOUND_EXPRESSION:
@@ -237,7 +234,7 @@ export function getConstantType(
237234
if (isString(child) || isSymbol(child)) {
238235
continue
239236
}
240-
const childType = getConstantType(child, resultCache)
237+
const childType = getConstantType(child, context)
241238
if (childType === ConstantTypes.NOT_CONSTANT) {
242239
return ConstantTypes.NOT_CONSTANT
243240
} else if (childType < returnType) {
@@ -256,15 +253,15 @@ export function getConstantType(
256253

257254
function getGeneratedPropsConstantType(
258255
node: PlainElementNode,
259-
resultCache: Map<TemplateChildNode, ConstantTypes>
256+
context: TransformContext
260257
): ConstantTypes {
261258
let returnType = ConstantTypes.CAN_STRINGIFY
262259
const props = getNodeProps(node)
263260
if (props && props.type === NodeTypes.JS_OBJECT_EXPRESSION) {
264261
const { properties } = props
265262
for (let i = 0; i < properties.length; i++) {
266263
const { key, value } = properties[i]
267-
const keyType = getConstantType(key, resultCache)
264+
const keyType = getConstantType(key, context)
268265
if (keyType === ConstantTypes.NOT_CONSTANT) {
269266
return keyType
270267
}
@@ -274,7 +271,7 @@ function getGeneratedPropsConstantType(
274271
if (value.type !== NodeTypes.SIMPLE_EXPRESSION) {
275272
return ConstantTypes.NOT_CONSTANT
276273
}
277-
const valueType = getConstantType(value, resultCache)
274+
const valueType = getConstantType(value, context)
278275
if (valueType === ConstantTypes.NOT_CONSTANT) {
279276
return valueType
280277
}

packages/compiler-core/src/transforms/transformElement.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ export const transformElement: NodeTransform = (node, context) => {
168168
type === NodeTypes.COMPOUND_EXPRESSION
169169
if (
170170
hasDynamicTextChild &&
171-
getConstantType(child) === ConstantTypes.NOT_CONSTANT
171+
getConstantType(child, context) === ConstantTypes.NOT_CONSTANT
172172
) {
173173
patchFlag |= PatchFlags.TEXT
174174
}
@@ -373,7 +373,7 @@ export function buildProps(
373373
value.type === NodeTypes.JS_CACHE_EXPRESSION ||
374374
((value.type === NodeTypes.SIMPLE_EXPRESSION ||
375375
value.type === NodeTypes.COMPOUND_EXPRESSION) &&
376-
getConstantType(value) > 0)
376+
getConstantType(value, context) > 0)
377377
) {
378378
// skip if the prop is a cached handler or has constant value
379379
return

packages/compiler-core/src/transforms/transformText.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ export const transformText: NodeTransform = (node, context) => {
8282
// mark dynamic text with flag so it gets patched inside a block
8383
if (
8484
!context.ssr &&
85-
getConstantType(child) === ConstantTypes.NOT_CONSTANT
85+
getConstantType(child, context) === ConstantTypes.NOT_CONSTANT
8686
) {
8787
callArgs.push(
8888
PatchFlags.TEXT +

0 commit comments

Comments
 (0)