Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(compat): maintain compatConfig option in legacy functional comp #4974

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/runtime-core/src/compat/componentFunctional.ts
Expand Up @@ -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

Expand Down
7 changes: 6 additions & 1 deletion packages/runtime-core/src/component.ts
Expand Up @@ -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<string, unknown>
Expand Down Expand Up @@ -111,6 +115,7 @@ export interface FunctionalComponent<P = {}, E extends EmitsOptions = {}>
emits?: E | (keyof E)[]
inheritAttrs?: boolean
displayName?: string
compatConfig?: CompatConfig
}

export interface ClassComponent {
Expand Down
111 changes: 73 additions & 38 deletions packages/vue-compat/__tests__/componentFunctional.spec.ts
Expand Up @@ -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)
])
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)
])
}
}
}

const vm = new Vue({
provide() {
return {
foo: 123
const vm = new Vue({
provide() {
return {
foo: 123
}
},
components: {
func
},
template: `<func class="foo" x="foo">hello</func>`
}).$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(
`"<div id=\\"foo\\" class=\\"foo\\"><div class=\\"inject\\">123</div><div class=\\"slot\\">hello</div></div>"`
)

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 })
}
},
components: {
func
},
template: `<func class="foo" x="foo">hello</func>`
}).$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(
`"<div id=\\"foo\\" class=\\"foo\\"><div class=\\"inject\\">123</div><div class=\\"slot\\">hello</div></div>"`
)

expect(
(
deprecationData[DeprecationTypes.COMPONENT_FUNCTIONAL].message as Function
)(func)
).toHaveBeenWarned()
}

const vm = new Vue({
components: { func },
template: `<func class="foo" x="foo">hello</func>`
}).$mount()

expect(vm.$el.outerHTML).toMatchInlineSnapshot(`"<div></div>"`)
expect(
(
deprecationData[DeprecationTypes.COMPONENT_FUNCTIONAL]
.message as Function
)(func)
).toHaveBeenWarned()
expect(
(deprecationData[DeprecationTypes.ATTR_FALSE_VALUE].message as Function)(
func
)
).not.toHaveBeenWarned()
})
})