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 { isArray, isFunction, isObject, isPromise } from '@vue/shared'
|
||||||
import { defineAsyncComponent } from '../apiAsyncComponent'
|
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 { isVNode } from '../vnode'
|
||||||
import { softAssertCompatEnabled } from './compatConfig'
|
import { isCompatEnabled, softAssertCompatEnabled } from './compatConfig'
|
||||||
import { DeprecationTypes } from './deprecations'
|
import { DeprecationTypes, warnDeprecation } from './deprecations'
|
||||||
|
import { getCompatListeners } from './instanceListeners'
|
||||||
|
import { compatH } from './renderFn'
|
||||||
|
|
||||||
export function convertLegacyComponent(comp: any): Component {
|
export function convertLegacyComponent(comp: any): Component {
|
||||||
// 2.x async component
|
// 2.x async component
|
||||||
if (
|
// since after disabling this, plain functions are still valid usage, do not
|
||||||
isFunction(comp) &&
|
// use softAssert here.
|
||||||
softAssertCompatEnabled(DeprecationTypes.COMPONENT_ASYNC, comp)
|
if (isFunction(comp) && isCompatEnabled(DeprecationTypes.COMPONENT_ASYNC)) {
|
||||||
) {
|
__DEV__ && warnDeprecation(DeprecationTypes.COMPONENT_ASYNC, comp)
|
||||||
return convertLegacyAsyncComponent(comp)
|
return convertLegacyAsyncComponent(comp)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,6 +87,56 @@ function convertLegacyAsyncComponent(comp: LegacyAsyncComponent) {
|
|||||||
return converted
|
return converted
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertLegacyFunctionalComponent(comp: ComponentOptions) {
|
const normalizedFunctionalComponentMap = new Map<
|
||||||
return comp.render as FunctionalComponent
|
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`
|
name ? ` <${name}>` : `s`
|
||||||
} should be explicitly created via \`defineAsyncComponent()\` ` +
|
} should be explicitly created via \`defineAsyncComponent()\` ` +
|
||||||
`in Vue 3. Plain functions will be treated as functional components in ` +
|
`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`
|
link: `https://v3.vuejs.org/guide/migration/async-components.html`
|
||||||
@ -327,13 +333,10 @@ const deprecationData: Record<DeprecationTypes, DeprecationData> = {
|
|||||||
`Functional component${
|
`Functional component${
|
||||||
name ? ` <${name}>` : `s`
|
name ? ` <${name}>` : `s`
|
||||||
} should be defined as a plain function in Vue 3. The "functional" ` +
|
} should be defined as a plain function in Vue 3. The "functional" ` +
|
||||||
`option has been removed.\n` +
|
`option has been removed. NOTE: Before migrating to use plain ` +
|
||||||
`NOTE: Before migrating, ensure that all async ` +
|
`functions for functional components, first make sure that all async ` +
|
||||||
`components have been upgraded to use \`defineAsyncComponent()\` and ` +
|
`components usage have been migrated and its compat behavior has ` +
|
||||||
`then disable compat for legacy async components with:` +
|
`been disabled.`
|
||||||
`\n\n configureCompat({ ${
|
|
||||||
DeprecationTypes.COMPONENT_ASYNC
|
|
||||||
}: false })\n`
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
link: `https://v3.vuejs.org/guide/migration/functional-components.html`
|
link: `https://v3.vuejs.org/guide/migration/functional-components.html`
|
||||||
|
@ -41,17 +41,21 @@ type LegacyVNodeChildren =
|
|||||||
| VNode
|
| VNode
|
||||||
| VNodeArrayChildren
|
| VNodeArrayChildren
|
||||||
|
|
||||||
export function h(
|
export function compatH(
|
||||||
type: string | Component,
|
type: string | Component,
|
||||||
children?: LegacyVNodeChildren
|
children?: LegacyVNodeChildren
|
||||||
): VNode
|
): VNode
|
||||||
export function h(
|
export function compatH(
|
||||||
type: string | Component,
|
type: string | Component,
|
||||||
props?: LegacyVNodeProps,
|
props?: LegacyVNodeProps,
|
||||||
children?: LegacyVNodeChildren
|
children?: LegacyVNodeChildren
|
||||||
): VNode
|
): 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
|
const l = arguments.length
|
||||||
if (l === 2) {
|
if (l === 2) {
|
||||||
if (isObject(propsOrChildren) && !isArray(propsOrChildren)) {
|
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 {
|
function convertLegacyProps(props: LegacyVNodeProps): Data & VNodeProps {
|
||||||
// TODO
|
// TODO
|
||||||
return {}
|
return props as any
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertLegacyDirectives(vnode: VNode, props: LegacyVNodeProps): VNode {
|
function convertLegacyDirectives(vnode: VNode, props: LegacyVNodeProps): VNode {
|
||||||
|
@ -597,31 +597,7 @@ export function applyOptions(
|
|||||||
// - watch (deferred since it relies on `this` access)
|
// - watch (deferred since it relies on `this` access)
|
||||||
|
|
||||||
if (injectOptions) {
|
if (injectOptions) {
|
||||||
if (isArray(injectOptions)) {
|
resolveInjections(injectOptions, ctx, checkDuplicateProperties)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (methods) {
|
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(
|
function callSyncHook(
|
||||||
name: 'beforeCreate' | 'created',
|
name: 'beforeCreate' | 'created',
|
||||||
type: LifecycleHooks,
|
type: LifecycleHooks,
|
||||||
|
Loading…
Reference in New Issue
Block a user