type RootNode,
type SimpleExpressionNode,
type SlotFunctionExpression,
+ type SlotsObjectProperty,
type TemplateChildNode,
type TemplateNode,
type TextCallNode,
type VNodeCall,
createArrayExpression,
+ createObjectProperty,
+ createSimpleExpression,
getVNodeBlockHelper,
getVNodeHelper,
} from '../ast'
}
let cachedAsArray = false
+ const slotCacheKeys = []
if (toCache.length === children.length && node.type === NodeTypes.ELEMENT) {
if (
node.tagType === ElementTypes.ELEMENT &&
// default slot
const slot = getSlotNode(node.codegenNode, 'default')
if (slot) {
+ slotCacheKeys.push(context.cached.length)
slot.returns = getCacheExpression(
createArrayExpression(slot.returns as TemplateChildNode[]),
)
slotName.arg &&
getSlotNode(parent.codegenNode, slotName.arg)
if (slot) {
+ slotCacheKeys.push(context.cached.length)
slot.returns = getCacheExpression(
createArrayExpression(slot.returns as TemplateChildNode[]),
)
if (!cachedAsArray) {
for (const child of toCache) {
+ slotCacheKeys.push(context.cached.length)
child.codegenNode = context.cache(child.codegenNode!)
}
}
+ // put the slot cached keys on the slot object, so that the cache
+ // can be removed when component unmounting to prevent memory leaks
+ if (
+ slotCacheKeys.length &&
+ node.type === NodeTypes.ELEMENT &&
+ node.tagType === ElementTypes.COMPONENT &&
+ node.codegenNode &&
+ node.codegenNode.type === NodeTypes.VNODE_CALL &&
+ node.codegenNode.children &&
+ !isArray(node.codegenNode.children) &&
+ node.codegenNode.children.type === NodeTypes.JS_OBJECT_EXPRESSION
+ ) {
+ node.codegenNode.children.properties.push(
+ createObjectProperty(
+ `__`,
+ createSimpleExpression(JSON.stringify(slotCacheKeys), false),
+ ) as SlotsObjectProperty,
+ )
+ }
+
function getCacheExpression(value: JSChildNode): CacheExpression {
const exp = context.cache(value)
// #6978, #7138, #7114
* @internal
*/
_?: SlotFlags
+ /**
+ * cache indexes for slot content
+ * @internal
+ */
+ __?: number[]
}
const isInternalKey = (key: string) => key[0] === '_' || key === '$stable'
// when rendering the optimized slots by manually written render function,
// do not copy the `slots._` compiler flag so that `renderSlot` creates
// slot Fragment with BAIL patchFlag to force full updates
- if (optimized || key !== '_') {
+ if (optimized || !isInternalKey(key)) {
slots[key] = children[key]
}
}
unregisterHMR(instance)
}
- const { bum, scope, job, subTree, um, m, a } = instance
+ const {
+ bum,
+ scope,
+ job,
+ subTree,
+ um,
+ m,
+ a,
+ parent,
+ slots: { __: slotCacheKeys },
+ } = instance
invalidateMount(m)
invalidateMount(a)
invokeArrayFns(bum)
}
+ // remove slots content from parent renderCache
+ if (parent && isArray(slotCacheKeys)) {
+ slotCacheKeys.forEach(v => {
+ parent.renderCache[v] = undefined
+ })
+ }
+
if (
__COMPAT__ &&
isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)