From: edison Date: Mon, 19 Jan 2026 01:14:39 +0000 (+0800) Subject: Revert "fix(runtime-core): resolve kebab-case slot names from in-DOM template…" ... X-Git-Tag: v3.5.27~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=35c360888b76f649fbbeb20c7d4d232fff735c92;p=thirdparty%2Fvuejs%2Fcore.git Revert "fix(runtime-core): resolve kebab-case slot names from in-DOM template…" (#14331) This reverts commit 7e554bf8975a6522cde00c261e8c6f1bffff1c24. --- diff --git a/packages/runtime-core/__tests__/componentSlots.spec.ts b/packages/runtime-core/__tests__/componentSlots.spec.ts index 9f0a8e5702..458731dd15 100644 --- a/packages/runtime-core/__tests__/componentSlots.spec.ts +++ b/packages/runtime-core/__tests__/componentSlots.spec.ts @@ -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]) - }) - }) - }) }) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index b24b57b4d4..4e1aa5e4d3 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -66,7 +66,6 @@ import { ShapeFlags, extend, getGlobalThis, - hyphenate, isArray, isFunction, isObject, @@ -1111,20 +1110,17 @@ const attrsProxyHandlers = __DEV__ }, } -const createSlotsProxyHandlers = ( - instance: ComponentInternalInstance, -): ProxyHandler => ({ - 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, } diff --git a/packages/runtime-core/src/components/KeepAlive.ts b/packages/runtime-core/src/components/KeepAlive.ts index 32883d8f00..55eaf86244 100644 --- a/packages/runtime-core/src/components/KeepAlive.ts +++ b/packages/runtime-core/src/components/KeepAlive.ts @@ -189,7 +189,7 @@ const KeepAliveImpl: ComponentOptions = { } // for e2e test - if (__DEV__ && __GLOBAL__) { + if (__DEV__ && __BROWSER__) { ;(instance as any).__keepAliveStorageContainer = storageContainer } } diff --git a/packages/runtime-core/src/helpers/renderSlot.ts b/packages/runtime-core/src/helpers/renderSlot.ts index 7f2615523d..2f1296bb13 100644 --- a/packages/runtime-core/src/helpers/renderSlot.ts +++ b/packages/runtime-core/src/helpers/renderSlot.ts @@ -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(