resolveDynamicComponent,
h,
serializeInner,
- createVNode
+ createVNode,
+ Comment,
+ VNode
} from '@vue/runtime-test'
import { mockWarn } from '@vue/shared'
baz: { render: () => 'baz' }
}
let foo, bar, baz // dynamic components
+ let dynamicVNode: VNode
const Child = {
render(this: any) {
return () => {
foo = resolveDynamicComponent('foo') // <component is="foo"/>
bar = resolveDynamicComponent(dynamicComponents.bar) // <component :is="bar"/>, function
+ dynamicVNode = createVNode(resolveDynamicComponent(null)) // <component :is="null"/>
return h(Child, () => {
// check inside child slots
baz = resolveDynamicComponent(dynamicComponents.baz) // <component :is="baz"/>, object
expect(foo).toBe(dynamicComponents.foo)
expect(bar).toBe(dynamicComponents.bar)
expect(baz).toBe(dynamicComponents.baz)
+ // should allow explicit falsy type to remove the component
+ expect(dynamicVNode!.type).toBe(Comment)
})
test('resolve dynamic component should fallback to plain element without warning', () => {
ComponentOptions
} from '../component'
import { Directive } from '../directives'
-import {
- camelize,
- capitalize,
- isString,
- isObject,
- isFunction
-} from '@vue/shared'
+import { camelize, capitalize, isString, isObject } from '@vue/shared'
import { warn } from '../warning'
const COMPONENTS = 'components'
return resolveAsset(COMPONENTS, name) || name
}
+export const NULL_DYNAMIC_COMPONENT = Symbol()
+
export function resolveDynamicComponent(
component: unknown
-): Component | string | undefined {
- if (!component) return
+): Component | string | typeof NULL_DYNAMIC_COMPONENT {
if (isString(component)) {
return resolveAsset(COMPONENTS, component, false) || component
- } else if (isFunction(component) || isObject(component)) {
- return component
+ } else {
+ // invalid types will fallthrough to createVNode and raise warning
+ return (component as any) || NULL_DYNAMIC_COMPONENT
}
}
import { TeleportImpl, isTeleport } from './components/Teleport'
import { currentRenderingInstance } from './componentRenderUtils'
import { RendererNode, RendererElement } from './renderer'
+import { NULL_DYNAMIC_COMPONENT } from './helpers/resolveAssets'
export const Fragment = (Symbol(__DEV__ ? 'Fragment' : undefined) as any) as {
__isFragment: true
: _createVNode) as typeof _createVNode
function _createVNode(
- type: VNodeTypes | ClassComponent,
+ type: VNodeTypes | ClassComponent | typeof NULL_DYNAMIC_COMPONENT,
props: (Data & VNodeProps) | null = null,
children: unknown = null,
patchFlag: number = 0,
dynamicProps: string[] | null = null,
isBlockNode = false
): VNode {
- if (!type) {
- if (__DEV__) {
+ if (!type || type === NULL_DYNAMIC_COMPONENT) {
+ if (__DEV__ && !type) {
warn(`Invalid vnode type when creating vnode: ${type}.`)
}
type = Comment