Skip to content

Commit d5d7904

Browse files
committed
fix(compiler-core): remove slot cache from parent renderCache during unmounting
1 parent 4f79253 commit d5d7904

File tree

5 files changed

+60
-3
lines changed

5 files changed

+60
-3
lines changed

Diff for: packages/compiler-core/__tests__/transforms/cacheStatic.spec.ts

+10
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,11 @@ describe('compiler: cacheStatic transform', () => {
170170
{
171171
/* _ slot flag */
172172
},
173+
{
174+
type: NodeTypes.JS_PROPERTY,
175+
key: { content: '__' },
176+
value: { content: '[0]' },
177+
},
173178
],
174179
})
175180
})
@@ -197,6 +202,11 @@ describe('compiler: cacheStatic transform', () => {
197202
{
198203
/* _ slot flag */
199204
},
205+
{
206+
type: NodeTypes.JS_PROPERTY,
207+
key: { content: '__' },
208+
value: { content: '[0]' },
209+
},
200210
],
201211
})
202212
})

Diff for: packages/compiler-core/src/transforms/cacheStatic.ts

+27
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,14 @@ import {
1212
type RootNode,
1313
type SimpleExpressionNode,
1414
type SlotFunctionExpression,
15+
type SlotsObjectProperty,
1516
type TemplateChildNode,
1617
type TemplateNode,
1718
type TextCallNode,
1819
type VNodeCall,
1920
createArrayExpression,
21+
createObjectProperty,
22+
createSimpleExpression,
2023
getVNodeBlockHelper,
2124
getVNodeHelper,
2225
} from '../ast'
@@ -140,6 +143,7 @@ function walk(
140143
}
141144

142145
let cachedAsArray = false
146+
const slotCacheKeys = []
143147
if (toCache.length === children.length && node.type === NodeTypes.ELEMENT) {
144148
if (
145149
node.tagType === ElementTypes.ELEMENT &&
@@ -163,6 +167,7 @@ function walk(
163167
// default slot
164168
const slot = getSlotNode(node.codegenNode, 'default')
165169
if (slot) {
170+
slotCacheKeys.push(context.cached.length)
166171
slot.returns = getCacheExpression(
167172
createArrayExpression(slot.returns as TemplateChildNode[]),
168173
)
@@ -186,6 +191,7 @@ function walk(
186191
slotName.arg &&
187192
getSlotNode(parent.codegenNode, slotName.arg)
188193
if (slot) {
194+
slotCacheKeys.push(context.cached.length)
189195
slot.returns = getCacheExpression(
190196
createArrayExpression(slot.returns as TemplateChildNode[]),
191197
)
@@ -196,10 +202,31 @@ function walk(
196202

197203
if (!cachedAsArray) {
198204
for (const child of toCache) {
205+
slotCacheKeys.push(context.cached.length)
199206
child.codegenNode = context.cache(child.codegenNode!)
200207
}
201208
}
202209

210+
// put the slot cached keys on the slot object, so that the cache
211+
// can be removed when component unmounting to prevent memory leaks
212+
if (
213+
slotCacheKeys.length &&
214+
node.type === NodeTypes.ELEMENT &&
215+
node.tagType === ElementTypes.COMPONENT &&
216+
node.codegenNode &&
217+
node.codegenNode.type === NodeTypes.VNODE_CALL &&
218+
node.codegenNode.children &&
219+
!isArray(node.codegenNode.children) &&
220+
node.codegenNode.children.type === NodeTypes.JS_OBJECT_EXPRESSION
221+
) {
222+
node.codegenNode.children.properties.push(
223+
createObjectProperty(
224+
`__`,
225+
createSimpleExpression(JSON.stringify(slotCacheKeys), false),
226+
) as SlotsObjectProperty,
227+
)
228+
}
229+
203230
function getCacheExpression(value: JSChildNode): CacheExpression {
204231
const exp = context.cache(value)
205232
// #6978, #7138, #7114

Diff for: packages/compiler-core/src/transforms/vSlot.ts

-1
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,6 @@ export function buildSlots(
342342
: hasForwardedSlots(node.children)
343343
? SlotFlags.FORWARDED
344344
: SlotFlags.STABLE
345-
346345
let slots = createObjectExpression(
347346
slotsProperties.concat(
348347
createObjectProperty(

Diff for: packages/runtime-core/src/componentSlots.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ export type RawSlots = {
7575
* @internal
7676
*/
7777
_?: SlotFlags
78+
/**
79+
* slot content cache keys
80+
*/
81+
__?: number[]
7882
}
7983

8084
const isInternalKey = (key: string) => key[0] === '_' || key === '$stable'
@@ -170,7 +174,7 @@ const assignSlots = (
170174
// when rendering the optimized slots by manually written render function,
171175
// do not copy the `slots._` compiler flag so that `renderSlot` creates
172176
// slot Fragment with BAIL patchFlag to force full updates
173-
if (optimized || key !== '_') {
177+
if (optimized || !key.startsWith('_')) {
174178
slots[key] = children[key]
175179
}
176180
}

Diff for: packages/runtime-core/src/renderer.ts

+18-1
Original file line numberDiff line numberDiff line change
@@ -2262,7 +2262,17 @@ function baseCreateRenderer(
22622262
unregisterHMR(instance)
22632263
}
22642264

2265-
const { bum, scope, job, subTree, um, m, a } = instance
2265+
const {
2266+
bum,
2267+
scope,
2268+
job,
2269+
subTree,
2270+
um,
2271+
m,
2272+
a,
2273+
parent,
2274+
slots: { __: slotCacheKeys },
2275+
} = instance
22662276
invalidateMount(m)
22672277
invalidateMount(a)
22682278

@@ -2271,6 +2281,13 @@ function baseCreateRenderer(
22712281
invokeArrayFns(bum)
22722282
}
22732283

2284+
// remove slots content from parent renderCache
2285+
if (parent && isArray(slotCacheKeys)) {
2286+
slotCacheKeys.forEach(v => {
2287+
parent.renderCache[v] = undefined
2288+
})
2289+
}
2290+
22742291
if (
22752292
__COMPAT__ &&
22762293
isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)

0 commit comments

Comments
 (0)