Skip to content

Commit ee97cf5

Browse files
authored
fix(compat): maintain compatConfig option in legacy functional comp (#4974)
1 parent 595a937 commit ee97cf5

File tree

3 files changed

+80
-39
lines changed

3 files changed

+80
-39
lines changed

packages/runtime-core/src/compat/componentFunctional.ts

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export function convertLegacyFunctionalComponent(comp: ComponentOptions) {
5555
}
5656
Func.props = comp.props
5757
Func.displayName = comp.name
58+
Func.compatConfig = comp.compatConfig
5859
// v2 functional components do not inherit attrs
5960
Func.inheritAttrs = false
6061

packages/runtime-core/src/component.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,11 @@ import { markAttrsAccessed } from './componentRenderUtils'
6060
import { currentRenderingInstance } from './componentRenderContext'
6161
import { startMeasure, endMeasure } from './profiling'
6262
import { convertLegacyRenderFn } from './compat/renderFn'
63-
import { globalCompatConfig, validateCompatConfig } from './compat/compatConfig'
63+
import {
64+
CompatConfig,
65+
globalCompatConfig,
66+
validateCompatConfig
67+
} from './compat/compatConfig'
6468
import { SchedulerJob } from './scheduler'
6569

6670
export type Data = Record<string, unknown>
@@ -111,6 +115,7 @@ export interface FunctionalComponent<P = {}, E extends EmitsOptions = {}>
111115
emits?: E | (keyof E)[]
112116
inheritAttrs?: boolean
113117
displayName?: string
118+
compatConfig?: CompatConfig
114119
}
115120

116121
export interface ClassComponent {

packages/vue-compat/__tests__/componentFunctional.spec.ts

+73-38
Original file line numberDiff line numberDiff line change
@@ -18,45 +18,80 @@ afterEach(() => {
1818
Vue.configureCompat({ MODE: 3 })
1919
})
2020

21-
test('COMPONENT_FUNCTIONAL', async () => {
22-
const func = {
23-
name: 'Func',
24-
functional: true,
25-
props: {
26-
x: String
27-
},
28-
inject: ['foo'],
29-
render: (h: any, { data, props, injections, slots }: any) => {
30-
return h('div', { id: props.x, class: data.class }, [
31-
h('div', { class: 'inject' }, injections.foo),
32-
h('div', { class: 'slot' }, slots().default)
33-
])
21+
describe('COMPONENT_FUNCTIONAL', () => {
22+
test('basic usage', async () => {
23+
const func = {
24+
name: 'Func',
25+
functional: true,
26+
props: {
27+
x: String
28+
},
29+
inject: ['foo'],
30+
render: (h: any, { data, props, injections, slots }: any) => {
31+
return h('div', { id: props.x, class: data.class }, [
32+
h('div', { class: 'inject' }, injections.foo),
33+
h('div', { class: 'slot' }, slots().default)
34+
])
35+
}
3436
}
35-
}
3637

37-
const vm = new Vue({
38-
provide() {
39-
return {
40-
foo: 123
38+
const vm = new Vue({
39+
provide() {
40+
return {
41+
foo: 123
42+
}
43+
},
44+
components: {
45+
func
46+
},
47+
template: `<func class="foo" x="foo">hello</func>`
48+
}).$mount()
49+
50+
expect(vm.$el.id).toBe('foo')
51+
expect(vm.$el.className).toBe('foo')
52+
expect(vm.$el.querySelector('.inject').textContent).toBe('123')
53+
expect(vm.$el.querySelector('.slot').textContent).toBe('hello')
54+
expect(vm.$el.outerHTML).toMatchInlineSnapshot(
55+
`"<div id=\\"foo\\" class=\\"foo\\"><div class=\\"inject\\">123</div><div class=\\"slot\\">hello</div></div>"`
56+
)
57+
58+
expect(
59+
(
60+
deprecationData[DeprecationTypes.COMPONENT_FUNCTIONAL]
61+
.message as Function
62+
)(func)
63+
).toHaveBeenWarned()
64+
})
65+
66+
test('copies compatConfig option', () => {
67+
const func = {
68+
name: 'Func',
69+
functional: true,
70+
compatConfig: {
71+
ATTR_FALSE_VALUE: 'suppress-warning' as const
72+
},
73+
render: (h: any) => {
74+
// should not render required: false due to compatConfig
75+
return h('div', { 'data-some-attr': false })
4176
}
42-
},
43-
components: {
44-
func
45-
},
46-
template: `<func class="foo" x="foo">hello</func>`
47-
}).$mount()
48-
49-
expect(vm.$el.id).toBe('foo')
50-
expect(vm.$el.className).toBe('foo')
51-
expect(vm.$el.querySelector('.inject').textContent).toBe('123')
52-
expect(vm.$el.querySelector('.slot').textContent).toBe('hello')
53-
expect(vm.$el.outerHTML).toMatchInlineSnapshot(
54-
`"<div id=\\"foo\\" class=\\"foo\\"><div class=\\"inject\\">123</div><div class=\\"slot\\">hello</div></div>"`
55-
)
56-
57-
expect(
58-
(
59-
deprecationData[DeprecationTypes.COMPONENT_FUNCTIONAL].message as Function
60-
)(func)
61-
).toHaveBeenWarned()
77+
}
78+
79+
const vm = new Vue({
80+
components: { func },
81+
template: `<func class="foo" x="foo">hello</func>`
82+
}).$mount()
83+
84+
expect(vm.$el.outerHTML).toMatchInlineSnapshot(`"<div></div>"`)
85+
expect(
86+
(
87+
deprecationData[DeprecationTypes.COMPONENT_FUNCTIONAL]
88+
.message as Function
89+
)(func)
90+
).toHaveBeenWarned()
91+
expect(
92+
(deprecationData[DeprecationTypes.ATTR_FALSE_VALUE].message as Function)(
93+
func
94+
)
95+
).not.toHaveBeenWarned()
96+
})
6297
})

0 commit comments

Comments
 (0)