diff --git a/packages/runtime-core/src/compat/componentFunctional.ts b/packages/runtime-core/src/compat/componentFunctional.ts index 80af32a1..1b1146bb 100644 --- a/packages/runtime-core/src/compat/componentFunctional.ts +++ b/packages/runtime-core/src/compat/componentFunctional.ts @@ -55,6 +55,7 @@ export function convertLegacyFunctionalComponent(comp: ComponentOptions) { } Func.props = comp.props Func.displayName = comp.name + Func.compatConfig = comp.compatConfig // v2 functional components do not inherit attrs Func.inheritAttrs = false diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 515bd16d..cda15d8b 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -60,7 +60,11 @@ import { markAttrsAccessed } from './componentRenderUtils' import { currentRenderingInstance } from './componentRenderContext' import { startMeasure, endMeasure } from './profiling' import { convertLegacyRenderFn } from './compat/renderFn' -import { globalCompatConfig, validateCompatConfig } from './compat/compatConfig' +import { + CompatConfig, + globalCompatConfig, + validateCompatConfig +} from './compat/compatConfig' import { SchedulerJob } from './scheduler' export type Data = Record @@ -111,6 +115,7 @@ export interface FunctionalComponent

emits?: E | (keyof E)[] inheritAttrs?: boolean displayName?: string + compatConfig?: CompatConfig } export interface ClassComponent { diff --git a/packages/vue-compat/__tests__/componentFunctional.spec.ts b/packages/vue-compat/__tests__/componentFunctional.spec.ts index 82587cbf..e17534ce 100644 --- a/packages/vue-compat/__tests__/componentFunctional.spec.ts +++ b/packages/vue-compat/__tests__/componentFunctional.spec.ts @@ -18,45 +18,80 @@ afterEach(() => { Vue.configureCompat({ MODE: 3 }) }) -test('COMPONENT_FUNCTIONAL', async () => { - const func = { - name: 'Func', - functional: true, - props: { - x: String - }, - inject: ['foo'], - render: (h: any, { data, props, injections, slots }: any) => { - return h('div', { id: props.x, class: data.class }, [ - h('div', { class: 'inject' }, injections.foo), - h('div', { class: 'slot' }, slots().default) - ]) - } - } - - const vm = new Vue({ - provide() { - return { - foo: 123 +describe('COMPONENT_FUNCTIONAL', () => { + test('basic usage', async () => { + const func = { + name: 'Func', + functional: true, + props: { + x: String + }, + inject: ['foo'], + render: (h: any, { data, props, injections, slots }: any) => { + return h('div', { id: props.x, class: data.class }, [ + h('div', { class: 'inject' }, injections.foo), + h('div', { class: 'slot' }, slots().default) + ]) } - }, - components: { - func - }, - template: `hello` - }).$mount() + } - expect(vm.$el.id).toBe('foo') - expect(vm.$el.className).toBe('foo') - expect(vm.$el.querySelector('.inject').textContent).toBe('123') - expect(vm.$el.querySelector('.slot').textContent).toBe('hello') - expect(vm.$el.outerHTML).toMatchInlineSnapshot( - `"

123
hello
"` - ) + const vm = new Vue({ + provide() { + return { + foo: 123 + } + }, + components: { + func + }, + template: `hello` + }).$mount() - expect( - ( - deprecationData[DeprecationTypes.COMPONENT_FUNCTIONAL].message as Function - )(func) - ).toHaveBeenWarned() + expect(vm.$el.id).toBe('foo') + expect(vm.$el.className).toBe('foo') + expect(vm.$el.querySelector('.inject').textContent).toBe('123') + expect(vm.$el.querySelector('.slot').textContent).toBe('hello') + expect(vm.$el.outerHTML).toMatchInlineSnapshot( + `"
123
hello
"` + ) + + expect( + ( + deprecationData[DeprecationTypes.COMPONENT_FUNCTIONAL] + .message as Function + )(func) + ).toHaveBeenWarned() + }) + + test('copies compatConfig option', () => { + const func = { + name: 'Func', + functional: true, + compatConfig: { + ATTR_FALSE_VALUE: 'suppress-warning' as const + }, + render: (h: any) => { + // should not render required: false due to compatConfig + return h('div', { 'data-some-attr': false }) + } + } + + const vm = new Vue({ + components: { func }, + template: `hello` + }).$mount() + + expect(vm.$el.outerHTML).toMatchInlineSnapshot(`"
"`) + expect( + ( + deprecationData[DeprecationTypes.COMPONENT_FUNCTIONAL] + .message as Function + )(func) + ).toHaveBeenWarned() + expect( + (deprecationData[DeprecationTypes.ATTR_FALSE_VALUE].message as Function)( + func + ) + ).not.toHaveBeenWarned() + }) })