فهرست منبع

feat(runtime-vapor): implement app plugin

三咲智子 Kevin Deng 2 سال پیش
والد
کامیت
d77c7ade77

+ 45 - 0
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)
+  })
+})

+ 40 - 0
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 = any[]> = Options extends unknown[]
+  ? (app: App, ...options: Options) => any
+  : (app: App, options: Options) => any
+
+export type ObjectPlugin<Options = any[]> = {
+  install: PluginInstallFunction<Options>
+}
+export type FunctionPlugin<Options = any[]> = PluginInstallFunction<Options> &
+  Partial<ObjectPlugin<Options>>
+
+export type Plugin<Options = any[]> =
+  | FunctionPlugin<Options>
+  | ObjectPlugin<Options>
+
 export interface App {
   version: string
   config: AppConfig
 
+  use<Options extends unknown[]>(
+    plugin: Plugin<Options>,
+    ...options: Options
+  ): this
+  use<Options>(plugin: Plugin<Options>, options: Options): this
+
   mount(
     rootContainer: ParentNode | string,
     isHydrate?: boolean,

+ 3 - 0
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'