diff --git a/packages/runtime-vapor/src/apiCreateVaporApp.ts b/packages/runtime-vapor/src/apiCreateVaporApp.ts index 0f1afef78..31218c6b3 100644 --- a/packages/runtime-vapor/src/apiCreateVaporApp.ts +++ b/packages/runtime-vapor/src/apiCreateVaporApp.ts @@ -1,8 +1,9 @@ -import { isFunction, isObject } from '@vue/shared' +import { NO, isFunction, isObject } from '@vue/shared' import { type Component, type ComponentInternalInstance, createComponentInstance, + validateComponentName, } from './component' import { warn } from './warning' import { version } from '.' @@ -60,6 +61,20 @@ export function createVaporApp( return app }, + component(name: string, component?: Component): any { + if (__DEV__) { + validateComponentName(name, context.config) + } + if (!component) { + return context.components[name] + } + if (__DEV__ && context.components[name]) { + warn(`Component "${name}" has already been registered in target app.`) + } + context.components[name] = component + return app + }, + mount(rootContainer): any { if (!instance) { instance = createComponentInstance( @@ -119,10 +134,12 @@ export function createAppContext(): AppContext { return { app: null as any, config: { + isNativeTag: NO, errorHandler: undefined, warnHandler: undefined, globalProperties: {}, }, + components: {}, provides: Object.create(null), } } @@ -151,6 +168,11 @@ export interface App { ): this use(plugin: Plugin, options: Options): this + component(name: string): Component | undefined + // TODO: DefineComponent + // component( + component(name: string, component: T): this + mount( rootContainer: ParentNode | string, isHydrate?: boolean, @@ -163,6 +185,9 @@ export interface App { } export interface AppConfig { + // @private + readonly isNativeTag: (tag: string) => boolean + errorHandler?: ( err: unknown, instance: ComponentInternalInstance | null, @@ -179,6 +204,7 @@ export interface AppConfig { export interface AppContext { app: App // for devtools config: AppConfig + components: Record provides: Record } diff --git a/packages/runtime-vapor/src/component.ts b/packages/runtime-vapor/src/component.ts index bb98adc85..b771d9b70 100644 --- a/packages/runtime-vapor/src/component.ts +++ b/packages/runtime-vapor/src/component.ts @@ -1,5 +1,5 @@ import { EffectScope, isRef } from '@vue/reactivity' -import { EMPTY_OBJ, hasOwn, isArray, isFunction } from '@vue/shared' +import { EMPTY_OBJ, hasOwn, isArray, isFunction, makeMap } from '@vue/shared' import type { Block } from './apiRender' import type { DirectiveBinding } from './directives' import { @@ -25,7 +25,11 @@ import { } from './componentSlots' import { VaporLifecycleHooks } from './apiLifecycle' import { warn } from './warning' -import { type AppContext, createAppContext } from './apiCreateVaporApp' +import { + type AppConfig, + type AppContext, + createAppContext, +} from './apiCreateVaporApp' import type { Data } from '@vue/runtime-shared' export type Component = FunctionalComponent | ObjectComponent @@ -362,6 +366,19 @@ export function createComponentInstance( return instance } +const isBuiltInTag = /*#__PURE__*/ makeMap('slot,component') + +export function validateComponentName( + name: string, + { isNativeTag }: AppConfig, +) { + if (isBuiltInTag(name) || isNativeTag(name)) { + warn( + 'Do not use built-in or reserved HTML elements as component id: ' + name, + ) + } +} + export function isVaporComponent( val: unknown, ): val is ComponentInternalInstance {