Skip to content

Commit 8b4d3dd

Browse files
authored
refactor(compiler-vapor): exclude special built-ins from withVaporCtx (#14010)
Also adds documentation to withVaporCtx explaining its purpose and exceptions.
1 parent 57c9e74 commit 8b4d3dd

File tree

3 files changed

+27
-6
lines changed

3 files changed

+27
-6
lines changed

packages/compiler-vapor/src/generators/component.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,12 @@ import { genEventHandler } from './event'
4040
import { genDirectiveModifiers, genDirectivesForElement } from './directive'
4141
import { genBlock } from './block'
4242
import { genModelHandler } from './vModel'
43-
import { isBuiltInComponent, isTransitionTag } from '../utils'
43+
import {
44+
isBuiltInComponent,
45+
isKeepAliveTag,
46+
isTeleportTag,
47+
isTransitionGroupTag,
48+
} from '../utils'
4449

4550
export function genCreateComponent(
4651
operation: CreateComponentIRNode,
@@ -460,7 +465,12 @@ function genSlotBlockWithProps(oper: SlotBlockIRNode, context: CodegenContext) {
460465

461466
if (
462467
node.type === NodeTypes.ELEMENT &&
463-
(!isBuiltInComponent(node.tag) || isTransitionTag(node.tag))
468+
// Not a real component
469+
!isTeleportTag(node.tag) &&
470+
// Needs to determine whether to activate/deactivate based on instance.parent being KeepAlive
471+
!isKeepAliveTag(node.tag) &&
472+
// Slot updates need to trigger TransitionGroup's onBeforeUpdate/onUpdated hook
473+
!isTransitionGroupTag(node.tag)
464474
) {
465475
// wrap with withVaporCtx to ensure correct currentInstance inside slot
466476
blockFn = [`${context.helper('withVaporCtx')}(`, ...blockFn, `)`]

packages/runtime-vapor/src/componentSlots.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,20 @@ export function getSlot(
114114
}
115115
}
116116

117+
/**
118+
* Wraps a slot function to execute in the parent component's context.
119+
*
120+
* This ensures that:
121+
* 1. Reactive effects created inside the slot (e.g., `renderEffect`) bind to the
122+
* parent's instance, so the parent's lifecycle hooks fire when the slot's
123+
* reactive dependencies change.
124+
* 2. Elements created in the slot inherit the parent's scopeId for proper style
125+
* scoping in scoped CSS.
126+
*
127+
* **Rationale**: Slots are defined in the parent's template, so the parent should
128+
* own the rendering context and be aware of updates.
129+
*
130+
*/
117131
export function withVaporCtx(fn: Function): BlockFn {
118132
const instance = currentInstance as VaporComponentInstance
119133
return (...args: any[]) => {

packages/runtime-vapor/src/components/TransitionGroup.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export const VaporTransitionGroup: ObjectVaporComponent = decorate({
6161

6262
let prevChildren: TransitionBlock[]
6363
let children: TransitionBlock[]
64-
let slottedBlock: Block
64+
const slottedBlock = slots.default && slots.default()
6565

6666
onBeforeUpdate(() => {
6767
prevChildren = []
@@ -88,7 +88,6 @@ export const VaporTransitionGroup: ObjectVaporComponent = decorate({
8888
if (!prevChildren.length) {
8989
return
9090
}
91-
9291
const moveClass = props.moveClass || `${props.name || 'v'}-move`
9392
const firstChild = getFirstConnectedChild(prevChildren)
9493
if (
@@ -122,8 +121,6 @@ export const VaporTransitionGroup: ObjectVaporComponent = decorate({
122121
prevChildren = []
123122
})
124123

125-
slottedBlock = slots.default && slots.default()
126-
127124
// store props and state on fragment for reusing during insert new items
128125
setTransitionHooksOnFragment(slottedBlock, {
129126
props: cssTransitionProps,

0 commit comments

Comments
 (0)