From: edison Date: Thu, 23 Oct 2025 02:32:51 +0000 (+0800) Subject: refactor(compiler-vapor): exclude special built-ins from withVaporCtx (#14010) X-Git-Tag: v3.6.0-alpha.3~17 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8b4d3dd4cd65114d41016b588ba638cf00bf2309;p=thirdparty%2Fvuejs%2Fcore.git refactor(compiler-vapor): exclude special built-ins from withVaporCtx (#14010) Also adds documentation to withVaporCtx explaining its purpose and exceptions. --- diff --git a/packages/compiler-vapor/src/generators/component.ts b/packages/compiler-vapor/src/generators/component.ts index f7cbfd3d24..38dd701704 100644 --- a/packages/compiler-vapor/src/generators/component.ts +++ b/packages/compiler-vapor/src/generators/component.ts @@ -40,7 +40,12 @@ import { genEventHandler } from './event' import { genDirectiveModifiers, genDirectivesForElement } from './directive' import { genBlock } from './block' import { genModelHandler } from './vModel' -import { isBuiltInComponent, isTransitionTag } from '../utils' +import { + isBuiltInComponent, + isKeepAliveTag, + isTeleportTag, + isTransitionGroupTag, +} from '../utils' export function genCreateComponent( operation: CreateComponentIRNode, @@ -460,7 +465,12 @@ function genSlotBlockWithProps(oper: SlotBlockIRNode, context: CodegenContext) { if ( node.type === NodeTypes.ELEMENT && - (!isBuiltInComponent(node.tag) || isTransitionTag(node.tag)) + // Not a real component + !isTeleportTag(node.tag) && + // Needs to determine whether to activate/deactivate based on instance.parent being KeepAlive + !isKeepAliveTag(node.tag) && + // Slot updates need to trigger TransitionGroup's onBeforeUpdate/onUpdated hook + !isTransitionGroupTag(node.tag) ) { // wrap with withVaporCtx to ensure correct currentInstance inside slot blockFn = [`${context.helper('withVaporCtx')}(`, ...blockFn, `)`] diff --git a/packages/runtime-vapor/src/componentSlots.ts b/packages/runtime-vapor/src/componentSlots.ts index c6bc3c9d03..b2a3ff5fb9 100644 --- a/packages/runtime-vapor/src/componentSlots.ts +++ b/packages/runtime-vapor/src/componentSlots.ts @@ -114,6 +114,20 @@ export function getSlot( } } +/** + * Wraps a slot function to execute in the parent component's context. + * + * This ensures that: + * 1. Reactive effects created inside the slot (e.g., `renderEffect`) bind to the + * parent's instance, so the parent's lifecycle hooks fire when the slot's + * reactive dependencies change. + * 2. Elements created in the slot inherit the parent's scopeId for proper style + * scoping in scoped CSS. + * + * **Rationale**: Slots are defined in the parent's template, so the parent should + * own the rendering context and be aware of updates. + * + */ export function withVaporCtx(fn: Function): BlockFn { const instance = currentInstance as VaporComponentInstance return (...args: any[]) => { diff --git a/packages/runtime-vapor/src/components/TransitionGroup.ts b/packages/runtime-vapor/src/components/TransitionGroup.ts index 8c54fa25a5..b1e86c87b2 100644 --- a/packages/runtime-vapor/src/components/TransitionGroup.ts +++ b/packages/runtime-vapor/src/components/TransitionGroup.ts @@ -61,7 +61,7 @@ export const VaporTransitionGroup: ObjectVaporComponent = decorate({ let prevChildren: TransitionBlock[] let children: TransitionBlock[] - let slottedBlock: Block + const slottedBlock = slots.default && slots.default() onBeforeUpdate(() => { prevChildren = [] @@ -88,7 +88,6 @@ export const VaporTransitionGroup: ObjectVaporComponent = decorate({ if (!prevChildren.length) { return } - const moveClass = props.moveClass || `${props.name || 'v'}-move` const firstChild = getFirstConnectedChild(prevChildren) if ( @@ -122,8 +121,6 @@ export const VaporTransitionGroup: ObjectVaporComponent = decorate({ prevChildren = [] }) - slottedBlock = slots.default && slots.default() - // store props and state on fragment for reusing during insert new items setTransitionHooksOnFragment(slottedBlock, { props: cssTransitionProps,