wip: async component compat
This commit is contained in:
parent
d7957a7440
commit
18cf63ff05
83
packages/runtime-core/src/compat/component.ts
Normal file
83
packages/runtime-core/src/compat/component.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import { isArray, isFunction, isObject, isPromise } from '@vue/shared/src'
|
||||||
|
import { defineAsyncComponent } from '../apiAsyncComponent'
|
||||||
|
import { Component, ComponentOptions, FunctionalComponent } from '../component'
|
||||||
|
import { isVNode } from '../vnode'
|
||||||
|
import { softAssertCompatEnabled } from './compatConfig'
|
||||||
|
import { DeprecationTypes } from './deprecations'
|
||||||
|
|
||||||
|
export function convertLegacyComponent(comp: any): Component {
|
||||||
|
// 2.x async component
|
||||||
|
if (
|
||||||
|
isFunction(comp) &&
|
||||||
|
softAssertCompatEnabled(DeprecationTypes.COMPONENT_ASYNC, comp)
|
||||||
|
) {
|
||||||
|
return convertLegacyAsyncComponent(comp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.x functional component
|
||||||
|
if (
|
||||||
|
isObject(comp) &&
|
||||||
|
comp.functional &&
|
||||||
|
softAssertCompatEnabled(DeprecationTypes.COMPONENT_FUNCTIONAL, comp)
|
||||||
|
) {
|
||||||
|
return convertLegacyFunctionalComponent(comp)
|
||||||
|
}
|
||||||
|
|
||||||
|
return comp
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LegacyAsyncOptions {
|
||||||
|
component: Promise<Component>
|
||||||
|
loading?: Component
|
||||||
|
error?: Component
|
||||||
|
delay?: number
|
||||||
|
timeout?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
type LegacyAsyncReturnValue = Promise<Component> | LegacyAsyncOptions
|
||||||
|
|
||||||
|
type LegacyAsyncComponent = (
|
||||||
|
resolve?: (res: LegacyAsyncReturnValue) => void,
|
||||||
|
reject?: (reason?: any) => void
|
||||||
|
) => LegacyAsyncReturnValue | undefined
|
||||||
|
|
||||||
|
const normalizedAsyncComponentMap = new Map<LegacyAsyncComponent, Component>()
|
||||||
|
|
||||||
|
function convertLegacyAsyncComponent(comp: LegacyAsyncComponent) {
|
||||||
|
if (normalizedAsyncComponentMap.has(comp)) {
|
||||||
|
return normalizedAsyncComponentMap.get(comp)!
|
||||||
|
}
|
||||||
|
|
||||||
|
// we have to call the function here due to how v2's API won't expose the
|
||||||
|
// options until we call it
|
||||||
|
let resolve: (res: LegacyAsyncReturnValue) => void
|
||||||
|
let reject: (reason?: any) => void
|
||||||
|
const fallbackPromise = new Promise<Component>((r, rj) => {
|
||||||
|
;(resolve = r), (reject = rj)
|
||||||
|
})
|
||||||
|
|
||||||
|
const res = comp(resolve!, reject!)
|
||||||
|
|
||||||
|
let converted: Component
|
||||||
|
if (isPromise(res)) {
|
||||||
|
converted = defineAsyncComponent(() => res)
|
||||||
|
} else if (isObject(res) && !isVNode(res) && !isArray(res)) {
|
||||||
|
converted = defineAsyncComponent({
|
||||||
|
loader: () => res.component,
|
||||||
|
loadingComponent: res.loading,
|
||||||
|
errorComponent: res.error,
|
||||||
|
delay: res.delay,
|
||||||
|
timeout: res.timeout
|
||||||
|
})
|
||||||
|
} else if (res == null) {
|
||||||
|
converted = defineAsyncComponent(() => fallbackPromise)
|
||||||
|
} else {
|
||||||
|
converted = comp as any // probably a v3 functional comp
|
||||||
|
}
|
||||||
|
normalizedAsyncComponentMap.set(comp, converted)
|
||||||
|
return converted
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertLegacyFunctionalComponent(comp: ComponentOptions) {
|
||||||
|
return comp.render as FunctionalComponent
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
formatComponentName,
|
formatComponentName,
|
||||||
|
getComponentName,
|
||||||
getCurrentInstance,
|
getCurrentInstance,
|
||||||
isRuntimeOnly
|
isRuntimeOnly
|
||||||
} from '../component'
|
} from '../component'
|
||||||
@ -46,7 +47,10 @@ export const enum DeprecationTypes {
|
|||||||
ATTR_ENUMERATED_COERSION = 'ATTR_ENUMERATED_COERSION',
|
ATTR_ENUMERATED_COERSION = 'ATTR_ENUMERATED_COERSION',
|
||||||
|
|
||||||
TRANSITION_CLASSES = 'TRANSITION_CLASSES',
|
TRANSITION_CLASSES = 'TRANSITION_CLASSES',
|
||||||
TRANSITION_GROUP_ROOT = 'TRANSITION_GROUP_ROOT'
|
TRANSITION_GROUP_ROOT = 'TRANSITION_GROUP_ROOT',
|
||||||
|
|
||||||
|
COMPONENT_ASYNC = 'COMPONENT_ASYNC',
|
||||||
|
COMPONENT_FUNCTIONAL = 'COMPONENT_FUNCTIONAL'
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeprecationData = {
|
type DeprecationData = {
|
||||||
@ -302,6 +306,39 @@ const deprecationData: Record<DeprecationTypes, DeprecationData> = {
|
|||||||
DeprecationTypes.TRANSITION_GROUP_ROOT
|
DeprecationTypes.TRANSITION_GROUP_ROOT
|
||||||
}: { enabled: false }})\n`,
|
}: { enabled: false }})\n`,
|
||||||
link: `https://v3.vuejs.org/guide/migration/transition-group.html`
|
link: `https://v3.vuejs.org/guide/migration/transition-group.html`
|
||||||
|
},
|
||||||
|
|
||||||
|
[DeprecationTypes.COMPONENT_ASYNC]: {
|
||||||
|
message: (comp: any) => {
|
||||||
|
const name = getComponentName(comp)
|
||||||
|
return (
|
||||||
|
`Async component${
|
||||||
|
name ? ` <${name}>` : `s`
|
||||||
|
} should be explicitly created via \`defineAsyncComponent()\` ` +
|
||||||
|
`in Vue 3. Plain functions will be treated as functional components in ` +
|
||||||
|
`non-compat build.`
|
||||||
|
)
|
||||||
|
},
|
||||||
|
link: `https://v3.vuejs.org/guide/migration/async-components.html`
|
||||||
|
},
|
||||||
|
|
||||||
|
[DeprecationTypes.COMPONENT_FUNCTIONAL]: {
|
||||||
|
message: (comp: any) => {
|
||||||
|
const name = getComponentName(comp)
|
||||||
|
return (
|
||||||
|
`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
|
||||||
|
}: { enabled: false }})\n`
|
||||||
|
)
|
||||||
|
},
|
||||||
|
link: `https://v3.vuejs.org/guide/migration/functional-components.html`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +41,7 @@ import { RendererNode, RendererElement } from './renderer'
|
|||||||
import { NULL_DYNAMIC_COMPONENT } from './helpers/resolveAssets'
|
import { NULL_DYNAMIC_COMPONENT } from './helpers/resolveAssets'
|
||||||
import { hmrDirtyComponents } from './hmr'
|
import { hmrDirtyComponents } from './hmr'
|
||||||
import { setCompiledSlotRendering } from './helpers/renderSlot'
|
import { setCompiledSlotRendering } from './helpers/renderSlot'
|
||||||
|
import { convertLegacyComponent } from './compat/component'
|
||||||
|
|
||||||
export const Fragment = (Symbol(__DEV__ ? 'Fragment' : undefined) as any) as {
|
export const Fragment = (Symbol(__DEV__ ? 'Fragment' : undefined) as any) as {
|
||||||
__isFragment: true
|
__isFragment: true
|
||||||
@ -358,6 +359,11 @@ function _createVNode(
|
|||||||
type = type.__vccOpts
|
type = type.__vccOpts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2.x async/functional component compat
|
||||||
|
if (__COMPAT__) {
|
||||||
|
type = convertLegacyComponent(type)
|
||||||
|
}
|
||||||
|
|
||||||
// class & style normalization.
|
// class & style normalization.
|
||||||
if (props) {
|
if (props) {
|
||||||
// for reactive or proxy objects, we need to clone it to enable mutation.
|
// for reactive or proxy objects, we need to clone it to enable mutation.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user