]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
Revert "fix(runtime-core): resolve kebab-case slot names from in-DOM template…" ...
authoredison <daiwei521@126.com>
Mon, 19 Jan 2026 01:14:39 +0000 (09:14 +0800)
committerGitHub <noreply@github.com>
Mon, 19 Jan 2026 01:14:39 +0000 (09:14 +0800)
This reverts commit 7e554bf8975a6522cde00c261e8c6f1bffff1c24.

packages/runtime-core/__tests__/componentSlots.spec.ts
packages/runtime-core/src/component.ts
packages/runtime-core/src/components/KeepAlive.ts
packages/runtime-core/src/helpers/renderSlot.ts

index 9f0a8e570288a401977cb64e8ed311c79c7b6363..458731dd150c9b3ac407b3868822b809d444cd51 100644 (file)
@@ -11,8 +11,6 @@ import {
 } from '@vue/runtime-test'
 import { createBlock, normalizeVNode } from '../src/vnode'
 import { createSlots } from '../src/helpers/createSlots'
-import { renderSlot } from '../src/helpers/renderSlot'
-import { setCurrentRenderingInstance } from '../src/componentRenderContext'
 
 describe('component: slots', () => {
   function renderWithSlots(slots: any): any {
@@ -463,118 +461,4 @@ describe('component: slots', () => {
     createApp(App).mount(root)
     expect(serializeInner(root)).toBe('foo')
   })
-
-  // in-DOM templates use kebab-case slot names
-  describe('in-DOM template kebab-case slot name resolution', () => {
-    beforeEach(() => {
-      __BROWSER__ = true
-    })
-
-    afterEach(() => {
-      __BROWSER__ = false
-    })
-
-    test('should resolve camelCase slot access to kebab-case via slots', () => {
-      const Comp = {
-        setup(_: any, { slots }: any) {
-          // Access with camelCase, but slot is passed with kebab-case
-          return () => slots.dropdownRender()
-        },
-      }
-
-      const App = {
-        setup() {
-          // Parent passes slot with kebab-case name (simulating in-DOM template)
-          return () =>
-            h(Comp, null, { 'dropdown-render': () => 'dropdown content' })
-        },
-      }
-
-      const root = nodeOps.createElement('div')
-      createApp(App).mount(root)
-      expect(serializeInner(root)).toBe('dropdown content')
-    })
-
-    test('should resolve camelCase slot access to kebab-case via slots (PROD)', () => {
-      __DEV__ = false
-      try {
-        const Comp = {
-          setup(_: any, { slots }: any) {
-            // Access with camelCase, but slot is passed with kebab-case
-            return () => slots.dropdownRender()
-          },
-        }
-
-        const App = {
-          setup() {
-            // Parent passes slot with kebab-case name (simulating in-DOM template)
-            return () =>
-              h(Comp, null, { 'dropdown-render': () => 'dropdown content' })
-          },
-        }
-
-        const root = nodeOps.createElement('div')
-        createApp(App).mount(root)
-        expect(serializeInner(root)).toBe('dropdown content')
-      } finally {
-        __DEV__ = true
-      }
-    })
-
-    test('should prefer exact match over kebab-case conversion via slots', () => {
-      const Comp = {
-        setup(_: any, { slots }: any) {
-          return () => slots.dropdownRender()
-        },
-      }
-
-      const App = {
-        setup() {
-          // Both exact match and kebab-case exist
-          return () =>
-            h(Comp, null, {
-              'dropdown-render': () => 'kebab',
-              dropdownRender: () => 'exact',
-            })
-        },
-      }
-
-      const root = nodeOps.createElement('div')
-      createApp(App).mount(root)
-      // exact match should take priority
-      expect(serializeInner(root)).toBe('exact')
-    })
-
-    // renderSlot tests
-    describe('renderSlot', () => {
-      beforeEach(() => {
-        setCurrentRenderingInstance({ type: {} } as any)
-      })
-
-      afterEach(() => {
-        setCurrentRenderingInstance(null)
-      })
-
-      test('should resolve camelCase slot name to kebab-case via renderSlot', () => {
-        let child: any
-        const vnode = renderSlot(
-          { 'dropdown-render': () => [(child = h('child'))] },
-          'dropdownRender',
-        )
-        expect(vnode.children).toEqual([child])
-      })
-
-      test('should prefer exact match over kebab-case conversion via renderSlot', () => {
-        let exactChild: any
-        const vnode = renderSlot(
-          {
-            'dropdown-render': () => [h('kebab')],
-            dropdownRender: () => [(exactChild = h('exact'))],
-          },
-          'dropdownRender',
-        )
-        expect(vnode.children).toEqual([exactChild])
-      })
-    })
-  })
 })
index b24b57b4d480763f0735dccd8ead1cc2146b2389..4e1aa5e4d38dffef4351343401b7e6be9234f2fb 100644 (file)
@@ -66,7 +66,6 @@ import {
   ShapeFlags,
   extend,
   getGlobalThis,
-  hyphenate,
   isArray,
   isFunction,
   isObject,
@@ -1111,20 +1110,17 @@ const attrsProxyHandlers = __DEV__
       },
     }
 
-const createSlotsProxyHandlers = (
-  instance: ComponentInternalInstance,
-): ProxyHandler<InternalSlots> => ({
-  get(target, key: string | symbol) {
-    if (__DEV__) {
+/**
+ * Dev-only
+ */
+function getSlotsProxy(instance: ComponentInternalInstance): Slots {
+  return new Proxy(instance.slots, {
+    get(target, key: string) {
       track(instance, TrackOpTypes.GET, '$slots')
-    }
-    // in-DOM templates use kebab-case slot names, only relevant in browser
-    return (
-      target[key as string] ||
-      (__BROWSER__ && typeof key === 'string' && target[hyphenate(key)])
-    )
-  },
-})
+      return target[key]
+    },
+  })
+}
 
 export function createSetupContext(
   instance: ComponentInternalInstance,
@@ -1166,13 +1162,7 @@ export function createSetupContext(
         )
       },
       get slots() {
-        return (
-          slotsProxy ||
-          (slotsProxy = new Proxy(
-            instance.slots,
-            createSlotsProxyHandlers(instance),
-          ))
-        )
+        return slotsProxy || (slotsProxy = getSlotsProxy(instance))
       },
       get emit() {
         return (event: string, ...args: any[]) => instance.emit(event, ...args)
@@ -1182,9 +1172,7 @@ export function createSetupContext(
   } else {
     return {
       attrs: new Proxy(instance.attrs, attrsProxyHandlers),
-      slots: __BROWSER__
-        ? new Proxy(instance.slots, createSlotsProxyHandlers(instance))
-        : instance.slots,
+      slots: instance.slots,
       emit: instance.emit,
       expose,
     }
index 32883d8f00f060a766b76084dfdd1ed457223be9..55eaf86244330d0cdf80bb0c221ec285e0084220 100644 (file)
@@ -189,7 +189,7 @@ const KeepAliveImpl: ComponentOptions = {
       }
 
       // for e2e test
-      if (__DEV__ && __GLOBAL__) {
+      if (__DEV__ && __BROWSER__) {
         ;(instance as any).__keepAliveStorageContainer = storageContainer
       }
     }
index 7f2615523d1ef4840f7ca06abbc1548643cddaf6..2f1296bb13e9310392a68e627e0f37d6715c43e4 100644 (file)
@@ -14,7 +14,7 @@ import {
   isVNode,
   openBlock,
 } from '../vnode'
-import { PatchFlags, SlotFlags, hyphenate, isSymbol } from '@vue/shared'
+import { PatchFlags, SlotFlags, isSymbol } from '@vue/shared'
 import { warn } from '../warning'
 import { isAsyncWrapper } from '../apiAsyncComponent'
 
@@ -53,8 +53,7 @@ export function renderSlot(
     )
   }
 
-  // in-DOM templates use kebab-case slot names, only relevant in browser
-  let slot = slots[name] || (__BROWSER__ && slots[hyphenate(name)])
+  let slot = slots[name]
 
   if (__DEV__ && slot && slot.length > 1) {
     warn(