]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler-vapor): prevent nested components from inheriting parent slots (#14158)
authoredison <daiwei521@126.com>
Tue, 2 Dec 2025 08:36:29 +0000 (16:36 +0800)
committerGitHub <noreply@github.com>
Tue, 2 Dec 2025 08:36:29 +0000 (16:36 +0800)
packages/compiler-vapor/__tests__/transforms/__snapshots__/vSlot.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/vSlot.spec.ts
packages/compiler-vapor/src/transforms/transformElement.ts

index 9b66bb6c8693eeaec5bca9e1b607f7d41d7b7536..e3251a687d9a29e784c25b99bd32642ee0516219 100644 (file)
@@ -228,6 +228,25 @@ export function render(_ctx) {
 }"
 `;
 
+exports[`compiler: transform slot > nested component should not inherit parent slots 1`] = `
+"import { resolveComponent as _resolveComponent, withVaporCtx as _withVaporCtx, createComponentWithFallback as _createComponentWithFallback } from 'vue';
+
+export function render(_ctx) {
+  const _component_Bar = _resolveComponent("Bar")
+  const _component_Foo = _resolveComponent("Foo")
+  const n2 = _createComponentWithFallback(_component_Foo, null, {
+    "header": _withVaporCtx(() => {
+      return null
+    }),
+    "default": _withVaporCtx(() => {
+      const n1 = _createComponentWithFallback(_component_Bar)
+      return n1
+    })
+  }, true)
+  return n2
+}"
+`;
+
 exports[`compiler: transform slot > nested component slot 1`] = `
 "import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback, withVaporCtx as _withVaporCtx } from 'vue';
 
index 64d1b4ac4a446ad38827e4b3187442aacd181fa2..093f1d577be87f7346cb22bbfbec9d53516b04af 100644 (file)
@@ -155,6 +155,16 @@ describe('compiler: transform slot', () => {
     })
   })
 
+  test('nested component should not inherit parent slots', () => {
+    const { code } = compileWithSlots(`
+      <Foo>
+        <template #header></template>
+        <Bar />
+      </Foo>
+    `)
+    expect(code).toMatchSnapshot()
+  })
+
   test('named slots w/ implicit default slot', () => {
     const { ir, code } = compileWithSlots(
       `<Comp>
index dc9c7e0aae04d197a54e124d639fb20e5a077349..312800a093af7266f04dfcfe846cef7bf01dd5b0 100644 (file)
@@ -37,6 +37,7 @@ import {
   type IRProps,
   type IRPropsDynamicAttribute,
   type IRPropsStatic,
+  type IRSlots,
   type VaporDirectiveNode,
 } from '../ir'
 import { EMPTY_EXPRESSION } from './utils'
@@ -51,6 +52,20 @@ export const isReservedProp: (key: string) => boolean = /*#__PURE__*/ makeMap(
 export const transformElement: NodeTransform = (node, context) => {
   let effectIndex = context.block.effect.length
   const getEffectIndex = () => effectIndex++
+
+  // If the element is a component, we need to isolate its slots context.
+  // This ensures that slots defined for this component are not accidentally
+  // inherited by its children components.
+  let parentSlots: IRSlots[] | undefined
+  if (
+    node.type === NodeTypes.ELEMENT &&
+    (node.tagType === ElementTypes.COMPONENT ||
+      context.options.isCustomElement(node.tag))
+  ) {
+    parentSlots = context.slots
+    context.slots = []
+  }
+
   return function postTransformElement() {
     ;({ node } = context)
     if (
@@ -96,6 +111,10 @@ export const transformElement: NodeTransform = (node, context) => {
         getEffectIndex,
       )
     }
+
+    if (parentSlots) {
+      context.slots = parentSlots
+    }
   }
 }