wip: compat for legacy functional component
This commit is contained in:
parent
d71c488540
commit
457a56e331
@ -1,16 +1,25 @@
|
||||
import { isArray, isFunction, isObject, isPromise } from '@vue/shared'
|
||||
import { defineAsyncComponent } from '../apiAsyncComponent'
|
||||
import { Component, ComponentOptions, FunctionalComponent } from '../component'
|
||||
import {
|
||||
Component,
|
||||
ComponentOptions,
|
||||
FunctionalComponent,
|
||||
getCurrentInstance
|
||||
} from '../component'
|
||||
import { resolveInjections } from '../componentOptions'
|
||||
import { InternalSlots } from '../componentSlots'
|
||||
import { isVNode } from '../vnode'
|
||||
import { softAssertCompatEnabled } from './compatConfig'
|
||||
import { DeprecationTypes } from './deprecations'
|
||||
import { isCompatEnabled, softAssertCompatEnabled } from './compatConfig'
|
||||
import { DeprecationTypes, warnDeprecation } from './deprecations'
|
||||
import { getCompatListeners } from './instanceListeners'
|
||||
import { compatH } from './renderFn'
|
||||
|
||||
export function convertLegacyComponent(comp: any): Component {
|
||||
// 2.x async component
|
||||
if (
|
||||
isFunction(comp) &&
|
||||
softAssertCompatEnabled(DeprecationTypes.COMPONENT_ASYNC, comp)
|
||||
) {
|
||||
// since after disabling this, plain functions are still valid usage, do not
|
||||
// use softAssert here.
|
||||
if (isFunction(comp) && isCompatEnabled(DeprecationTypes.COMPONENT_ASYNC)) {
|
||||
__DEV__ && warnDeprecation(DeprecationTypes.COMPONENT_ASYNC, comp)
|
||||
return convertLegacyAsyncComponent(comp)
|
||||
}
|
||||
|
||||
@ -78,6 +87,56 @@ function convertLegacyAsyncComponent(comp: LegacyAsyncComponent) {
|
||||
return converted
|
||||
}
|
||||
|
||||
function convertLegacyFunctionalComponent(comp: ComponentOptions) {
|
||||
return comp.render as FunctionalComponent
|
||||
const normalizedFunctionalComponentMap = new Map<
|
||||
ComponentOptions,
|
||||
FunctionalComponent
|
||||
>()
|
||||
|
||||
const legacySlotProxyHandlers: ProxyHandler<InternalSlots> = {
|
||||
get(target, key: string) {
|
||||
const slot = target[key]
|
||||
return slot && slot()
|
||||
}
|
||||
}
|
||||
|
||||
function convertLegacyFunctionalComponent(comp: ComponentOptions) {
|
||||
if (normalizedFunctionalComponentMap.has(comp)) {
|
||||
return normalizedFunctionalComponentMap.get(comp)!
|
||||
}
|
||||
|
||||
const legacyFn = comp.render as any
|
||||
|
||||
const Func: FunctionalComponent = (props, ctx) => {
|
||||
const instance = getCurrentInstance()!
|
||||
|
||||
const legacyCtx = {
|
||||
props,
|
||||
children: instance.vnode.children || [],
|
||||
data: instance.vnode.props || {},
|
||||
scopedSlots: ctx.slots,
|
||||
parent: instance.parent && instance.parent.proxy,
|
||||
get slots() {
|
||||
return new Proxy(ctx.slots, legacySlotProxyHandlers)
|
||||
},
|
||||
get listeners() {
|
||||
return getCompatListeners(instance)
|
||||
},
|
||||
get injections() {
|
||||
if (comp.inject) {
|
||||
const injections = {}
|
||||
resolveInjections(comp.inject, {})
|
||||
return injections
|
||||
}
|
||||
return {}
|
||||
}
|
||||
}
|
||||
return legacyFn(compatH, legacyCtx)
|
||||
}
|
||||
Func.props = comp.props
|
||||
Func.displayName = comp.name
|
||||
// v2 functional components do not inherit attrs
|
||||
Func.inheritAttrs = false
|
||||
|
||||
normalizedFunctionalComponentMap.set(comp, Func)
|
||||
return Func
|
||||
}
|
||||
|
@ -314,7 +314,13 @@ const deprecationData: Record<DeprecationTypes, DeprecationData> = {
|
||||
name ? ` <${name}>` : `s`
|
||||
} should be explicitly created via \`defineAsyncComponent()\` ` +
|
||||
`in Vue 3. Plain functions will be treated as functional components in ` +
|
||||
`non-compat build.`
|
||||
`non-compat build. If you have already migrated all async component ` +
|
||||
`usage and intend to use plain functions for functional components, ` +
|
||||
`you can disable the compat behavior and suppress this ` +
|
||||
`warning with:` +
|
||||
`\n\n configureCompat({ ${
|
||||
DeprecationTypes.COMPONENT_ASYNC
|
||||
}: false })\n`
|
||||
)
|
||||
},
|
||||
link: `https://v3.vuejs.org/guide/migration/async-components.html`
|
||||
@ -327,13 +333,10 @@ const deprecationData: Record<DeprecationTypes, DeprecationData> = {
|
||||
`Functional component${
|
||||
name ? ` <${name}>` : `s`
|
||||
} should be defined as a plain function in Vue 3. The "functional" ` +
|
||||
`option has been removed.\n` +
|
||||
`NOTE: Before migrating, ensure that all async ` +
|
||||
`components have been upgraded to use \`defineAsyncComponent()\` and ` +
|
||||
`then disable compat for legacy async components with:` +
|
||||
`\n\n configureCompat({ ${
|
||||
DeprecationTypes.COMPONENT_ASYNC
|
||||
}: false })\n`
|
||||
`option has been removed. NOTE: Before migrating to use plain ` +
|
||||
`functions for functional components, first make sure that all async ` +
|
||||
`components usage have been migrated and its compat behavior has ` +
|
||||
`been disabled.`
|
||||
)
|
||||
},
|
||||
link: `https://v3.vuejs.org/guide/migration/functional-components.html`
|
||||
|
@ -41,17 +41,21 @@ type LegacyVNodeChildren =
|
||||
| VNode
|
||||
| VNodeArrayChildren
|
||||
|
||||
export function h(
|
||||
export function compatH(
|
||||
type: string | Component,
|
||||
children?: LegacyVNodeChildren
|
||||
): VNode
|
||||
export function h(
|
||||
export function compatH(
|
||||
type: string | Component,
|
||||
props?: LegacyVNodeProps,
|
||||
children?: LegacyVNodeChildren
|
||||
): VNode
|
||||
|
||||
export function h(type: any, propsOrChildren?: any, children?: any): VNode {
|
||||
export function compatH(
|
||||
type: any,
|
||||
propsOrChildren?: any,
|
||||
children?: any
|
||||
): VNode {
|
||||
const l = arguments.length
|
||||
if (l === 2) {
|
||||
if (isObject(propsOrChildren) && !isArray(propsOrChildren)) {
|
||||
@ -85,7 +89,7 @@ export function h(type: any, propsOrChildren?: any, children?: any): VNode {
|
||||
|
||||
function convertLegacyProps(props: LegacyVNodeProps): Data & VNodeProps {
|
||||
// TODO
|
||||
return {}
|
||||
return props as any
|
||||
}
|
||||
|
||||
function convertLegacyDirectives(vnode: VNode, props: LegacyVNodeProps): VNode {
|
||||
|
@ -597,31 +597,7 @@ export function applyOptions(
|
||||
// - watch (deferred since it relies on `this` access)
|
||||
|
||||
if (injectOptions) {
|
||||
if (isArray(injectOptions)) {
|
||||
for (let i = 0; i < injectOptions.length; i++) {
|
||||
const key = injectOptions[i]
|
||||
ctx[key] = inject(key)
|
||||
if (__DEV__) {
|
||||
checkDuplicateProperties!(OptionTypes.INJECT, key)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const key in injectOptions) {
|
||||
const opt = injectOptions[key]
|
||||
if (isObject(opt)) {
|
||||
ctx[key] = inject(
|
||||
opt.from || key,
|
||||
opt.default,
|
||||
true /* treat default function as factory */
|
||||
)
|
||||
} else {
|
||||
ctx[key] = inject(opt)
|
||||
}
|
||||
if (__DEV__) {
|
||||
checkDuplicateProperties!(OptionTypes.INJECT, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
resolveInjections(injectOptions, ctx, checkDuplicateProperties)
|
||||
}
|
||||
|
||||
if (methods) {
|
||||
@ -842,6 +818,38 @@ export function applyOptions(
|
||||
}
|
||||
}
|
||||
|
||||
export function resolveInjections(
|
||||
injectOptions: ComponentInjectOptions,
|
||||
ctx: any,
|
||||
checkDuplicateProperties = NOOP as any
|
||||
) {
|
||||
if (isArray(injectOptions)) {
|
||||
for (let i = 0; i < injectOptions.length; i++) {
|
||||
const key = injectOptions[i]
|
||||
ctx[key] = inject(key)
|
||||
if (__DEV__) {
|
||||
checkDuplicateProperties!(OptionTypes.INJECT, key)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const key in injectOptions) {
|
||||
const opt = injectOptions[key]
|
||||
if (isObject(opt)) {
|
||||
ctx[key] = inject(
|
||||
opt.from || key,
|
||||
opt.default,
|
||||
true /* treat default function as factory */
|
||||
)
|
||||
} else {
|
||||
ctx[key] = inject(opt)
|
||||
}
|
||||
if (__DEV__) {
|
||||
checkDuplicateProperties!(OptionTypes.INJECT, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function callSyncHook(
|
||||
name: 'beforeCreate' | 'created',
|
||||
type: LifecycleHooks,
|
||||
|
Loading…
Reference in New Issue
Block a user