diff --git a/packages/runtime-vapor/__tests__/apiCreateVaporApp.spec.ts b/packages/runtime-vapor/__tests__/apiCreateVaporApp.spec.ts new file mode 100644 index 000000000..715f3353e --- /dev/null +++ b/packages/runtime-vapor/__tests__/apiCreateVaporApp.spec.ts @@ -0,0 +1,45 @@ +import { type Component, type Plugin, createVaporApp, inject } from '../src' +;`` +describe('api: createApp', () => { + test('use', () => { + const PluginA: Plugin = app => app.provide('foo', 1) + const PluginB: Plugin = { + install: (app, arg1, arg2) => app.provide('bar', arg1 + arg2), + } + class PluginC { + someProperty = {} + static install() { + app.provide('baz', 2) + } + } + const PluginD: any = undefined + + const Root: Component = { + setup() { + const foo = inject('foo') + const bar = inject('bar') + return document.createTextNode(`${foo},${bar}`) + }, + } + + const app = createVaporApp(Root) + app.use(PluginA) + app.use(PluginB, 1, 1) + app.use(PluginC) + + const root = document.createElement('div') + app.mount(root) + expect(root.innerHTML).toBe(`1,2`) + + app.use(PluginA) + expect( + `Plugin has already been applied to target app`, + ).toHaveBeenWarnedTimes(1) + + app.use(PluginD) + expect( + `A plugin must either be a function or an object with an "install" ` + + `function.`, + ).toHaveBeenWarnedTimes(1) + }) +}) diff --git a/packages/runtime-vapor/src/apiCreateVaporApp.ts b/packages/runtime-vapor/src/apiCreateVaporApp.ts index 6e59b279c..0f1afef78 100644 --- a/packages/runtime-vapor/src/apiCreateVaporApp.ts +++ b/packages/runtime-vapor/src/apiCreateVaporApp.ts @@ -21,6 +21,8 @@ export function createVaporApp( } const context = createAppContext() + const installedPlugins = new WeakSet() + let instance: ComponentInternalInstance const app: App = { @@ -40,6 +42,24 @@ export function createVaporApp( } }, + use(plugin: Plugin, ...options: any[]) { + if (installedPlugins.has(plugin)) { + __DEV__ && warn(`Plugin has already been applied to target app.`) + } else if (plugin && isFunction(plugin.install)) { + installedPlugins.add(plugin) + plugin.install(app, ...options) + } else if (isFunction(plugin)) { + installedPlugins.add(plugin) + plugin(app, ...options) + } else if (__DEV__) { + warn( + `A plugin must either be a function or an object with an "install" ` + + `function.`, + ) + } + return app + }, + mount(rootContainer): any { if (!instance) { instance = createComponentInstance( @@ -107,10 +127,30 @@ export function createAppContext(): AppContext { } } +type PluginInstallFunction = Options extends unknown[] + ? (app: App, ...options: Options) => any + : (app: App, options: Options) => any + +export type ObjectPlugin = { + install: PluginInstallFunction +} +export type FunctionPlugin = PluginInstallFunction & + Partial> + +export type Plugin = + | FunctionPlugin + | ObjectPlugin + export interface App { version: string config: AppConfig + use( + plugin: Plugin, + ...options: Options + ): this + use(plugin: Plugin, options: Options): this + mount( rootContainer: ParentNode | string, isHydrate?: boolean, diff --git a/packages/runtime-vapor/src/index.ts b/packages/runtime-vapor/src/index.ts index b5f4235c4..959db2b69 100644 --- a/packages/runtime-vapor/src/index.ts +++ b/packages/runtime-vapor/src/index.ts @@ -121,6 +121,9 @@ export { type App, type AppConfig, type AppContext, + type Plugin, + type ObjectPlugin, + type FunctionPlugin, } from './apiCreateVaporApp' export { createIf } from './apiCreateIf' export { createFor } from './apiCreateFor'