Skip to content

Commit 91700fb

Browse files
committed
refactor(compiler-core): simplify hoistStatic check for nodes without patchFlag
close #1912
1 parent 255a2bd commit 91700fb

File tree

4 files changed

+42
-24
lines changed

4 files changed

+42
-24
lines changed

packages/compiler-core/__tests__/transforms/__snapshots__/hoistStatic.spec.ts.snap

+16
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,22 @@ return function render(_ctx, _cache) {
271271
}"
272272
`;
273273
274+
exports[`compiler: hoistStatic transform prefixIdentifiers should NOT hoist keyed template v-for with plain element child 1`] = `
275+
"const _Vue = Vue
276+
277+
return function render(_ctx, _cache) {
278+
with (_ctx) {
279+
const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createBlock: _createBlock, createVNode: _createVNode } = _Vue
280+
281+
return (_openBlock(), _createBlock(\\"div\\", null, [
282+
(_openBlock(true), _createBlock(_Fragment, null, _renderList(items, (item) => {
283+
return (_openBlock(), _createBlock(\\"span\\", { key: item }))
284+
}), 128 /* KEYED_FRAGMENT */))
285+
]))
286+
}
287+
}"
288+
`;
289+
274290
exports[`compiler: hoistStatic transform should NOT hoist components 1`] = `
275291
"const _Vue = Vue
276292

packages/compiler-core/__tests__/transforms/hoistStatic.spec.ts

+8
Original file line numberDiff line numberDiff line change
@@ -600,5 +600,13 @@ describe('compiler: hoistStatic transform', () => {
600600
}).code
601601
).toMatchSnapshot()
602602
})
603+
604+
test('should NOT hoist keyed template v-for with plain element child', () => {
605+
const root = transformWithHoist(
606+
`<div><template v-for="item in items" :key="item"><span/></template></div>`
607+
)
608+
expect(root.hoists.length).toBe(0)
609+
expect(generate(root).code).toMatchSnapshot()
610+
})
603611
})
604612
})

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

+15-22
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,12 @@ import {
77
PlainElementNode,
88
ComponentNode,
99
TemplateNode,
10-
ElementNode,
1110
VNodeCall,
1211
ParentNode
1312
} from '../ast'
1413
import { TransformContext } from '../transform'
1514
import { PatchFlags, isString, isSymbol } from '@vue/shared'
16-
import { isSlotOutlet, findProp } from '../utils'
15+
import { isSlotOutlet } from '../utils'
1716

1817
export function hoistStatic(root: RootNode, context: TransformContext) {
1918
walk(
@@ -93,8 +92,7 @@ function walk(
9392
(!flag ||
9493
flag === PatchFlags.NEED_PATCH ||
9594
flag === PatchFlags.TEXT) &&
96-
!hasDynamicKeyOrRef(child) &&
97-
!hasCachedProps(child)
95+
!hasNonHoistableProps(child)
9896
) {
9997
const props = getNodeProps(child)
10098
if (props) {
@@ -156,7 +154,7 @@ export function getStaticType(
156154
return StaticType.NOT_STATIC
157155
}
158156
const flag = getPatchFlag(codegenNode)
159-
if (!flag && !hasDynamicKeyOrRef(node) && !hasCachedProps(node)) {
157+
if (!flag && !hasNonHoistableProps(node)) {
160158
// element self is static. check its children.
161159
let returnType = StaticType.FULL_STATIC
162160
for (let i = 0; i < node.children.length; i++) {
@@ -238,28 +236,23 @@ export function getStaticType(
238236
}
239237
}
240238

241-
function hasDynamicKeyOrRef(node: ElementNode): boolean {
242-
return !!(findProp(node, 'key', true) || findProp(node, 'ref', true))
243-
}
244-
245-
function hasCachedProps(node: PlainElementNode): boolean {
246-
if (__BROWSER__) {
247-
return false
248-
}
239+
/**
240+
* Even for a node with no patch flag, it is possible for it to contain
241+
* non-hoistable expressions that refers to scope variables, e.g. compiler
242+
* injected keys or cached event handlers. Therefore we need to always check the
243+
* codegenNode's props to be sure.
244+
*/
245+
function hasNonHoistableProps(node: PlainElementNode): boolean {
249246
const props = getNodeProps(node)
250247
if (props && props.type === NodeTypes.JS_OBJECT_EXPRESSION) {
251248
const { properties } = props
252249
for (let i = 0; i < properties.length; i++) {
253-
const val = properties[i].value
254-
if (val.type === NodeTypes.JS_CACHE_EXPRESSION) {
255-
return true
256-
}
257-
// merged event handlers
250+
const { key, value } = properties[i]
258251
if (
259-
val.type === NodeTypes.JS_ARRAY_EXPRESSION &&
260-
val.elements.some(
261-
e => !isString(e) && e.type === NodeTypes.JS_CACHE_EXPRESSION
262-
)
252+
key.type !== NodeTypes.SIMPLE_EXPRESSION ||
253+
!key.isStatic ||
254+
(value.type !== NodeTypes.SIMPLE_EXPRESSION ||
255+
(!value.isStatic && !value.isConstant))
263256
) {
264257
return true
265258
}

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ import {
1919
BlockCodegenNode,
2020
IfNode,
2121
createVNodeCall,
22-
AttributeNode
22+
AttributeNode,
23+
locStub
2324
} from '../ast'
2425
import { createCompilerError, ErrorCodes } from '../errors'
2526
import { processExpression } from './transformExpression'
@@ -222,7 +223,7 @@ function createChildrenCodegenNode(
222223
const { helper } = context
223224
const keyProperty = createObjectProperty(
224225
`key`,
225-
createSimpleExpression(`${keyIndex}`, false)
226+
createSimpleExpression(`${keyIndex}`, false, locStub, true)
226227
)
227228
const { children } = branch
228229
const firstChild = children[0]

0 commit comments

Comments
 (0)