]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler-core): force dynamic slots when slot referencing scope vars (#9427)
authoredison <daiwei521@126.com>
Tue, 2 Sep 2025 09:24:56 +0000 (17:24 +0800)
committerGitHub <noreply@github.com>
Tue, 2 Sep 2025 09:24:56 +0000 (17:24 +0800)
close #9380

packages/compiler-core/__tests__/transforms/vSlot.spec.ts
packages/compiler-core/src/transforms/vSlot.ts

index e0f44a064fb091c8ccb2bf75533f3c45832223e4..1213e218e662bb1285873e999b54da069ed0cae2 100644 (file)
@@ -478,7 +478,10 @@ describe('compiler: transform component slots', () => {
   })
 
   test('should only force dynamic slots when actually using scope vars w/ prefixIdentifiers: true', () => {
-    function assertDynamicSlots(template: string, shouldForce: boolean) {
+    function assertDynamicSlots(
+      template: string,
+      expectedPatchFlag?: PatchFlags,
+    ) {
       const { root } = parseWithSlots(template, { prefixIdentifiers: true })
       let flag: any
       if (root.children[0].type === NodeTypes.FOR) {
@@ -491,8 +494,8 @@ describe('compiler: transform component slots', () => {
           .children[0] as ComponentNode
         flag = (innerComp.codegenNode as VNodeCall).patchFlag
       }
-      if (shouldForce) {
-        expect(flag).toBe(PatchFlags.DYNAMIC_SLOTS)
+      if (expectedPatchFlag) {
+        expect(flag).toBe(expectedPatchFlag)
       } else {
         expect(flag).toBeUndefined()
       }
@@ -502,14 +505,13 @@ describe('compiler: transform component slots', () => {
       `<div v-for="i in list">
         <Comp v-slot="bar">foo</Comp>
       </div>`,
-      false,
     )
 
     assertDynamicSlots(
       `<div v-for="i in list">
         <Comp v-slot="bar">{{ i }}</Comp>
       </div>`,
-      true,
+      PatchFlags.DYNAMIC_SLOTS,
     )
 
     // reference the component's own slot variable should not force dynamic slots
@@ -517,14 +519,13 @@ describe('compiler: transform component slots', () => {
       `<Comp v-slot="foo">
         <Comp v-slot="bar">{{ bar }}</Comp>
       </Comp>`,
-      false,
     )
 
     assertDynamicSlots(
       `<Comp v-slot="foo">
         <Comp v-slot="bar">{{ foo }}</Comp>
       </Comp>`,
-      true,
+      PatchFlags.DYNAMIC_SLOTS,
     )
 
     // #2564
@@ -532,14 +533,35 @@ describe('compiler: transform component slots', () => {
       `<div v-for="i in list">
         <Comp v-slot="bar"><button @click="fn(i)" /></Comp>
       </div>`,
-      true,
+      PatchFlags.DYNAMIC_SLOTS,
     )
 
     assertDynamicSlots(
       `<div v-for="i in list">
         <Comp v-slot="bar"><button @click="fn()" /></Comp>
       </div>`,
-      false,
+    )
+
+    // #9380
+    assertDynamicSlots(
+      `<div v-for="i in list">
+        <Comp :i="i">foo</Comp>
+      </div>`,
+      PatchFlags.PROPS,
+    )
+
+    assertDynamicSlots(
+      `<div v-for="i in list">
+        <Comp v-slot="{ value = i }"><button @click="fn()" /></Comp>
+      </div>`,
+      PatchFlags.DYNAMIC_SLOTS,
+    )
+
+    assertDynamicSlots(
+      `<div v-for="i in list">
+        <Comp v-slot:[i]><button @click="fn()" /></Comp>
+      </div>`,
+      PatchFlags.DYNAMIC_SLOTS,
     )
   })
 
index 43296dcc9b67a606c4cfafb4309a28bf41b5d1a3..4681791f8d577cf0e5a4f5ca4afe606b7d2644f8 100644 (file)
@@ -131,9 +131,17 @@ export function buildSlots(
   // since it likely uses a scope variable.
   let hasDynamicSlots = context.scopes.vSlot > 0 || context.scopes.vFor > 0
   // with `prefixIdentifiers: true`, this can be further optimized to make
-  // it dynamic only when the slot actually uses the scope variables.
+  // it dynamic when
+  // 1. the slot arg or exp uses the scope variables.
+  // 2. the slot children use the scope variables.
   if (!__BROWSER__ && !context.ssr && context.prefixIdentifiers) {
-    hasDynamicSlots = hasScopeRef(node, context.identifiers)
+    hasDynamicSlots =
+      node.props.some(
+        prop =>
+          isVSlot(prop) &&
+          (hasScopeRef(prop.arg, context.identifiers) ||
+            hasScopeRef(prop.exp, context.identifiers)),
+      ) || children.some(child => hasScopeRef(child, context.identifiers))
   }
 
   // 1. Check for slot with slotProps on component itself.