diff --git a/packages/designer/src/plugin/plugin-manager.ts b/packages/designer/src/plugin/plugin-manager.ts index 3f8f399b4..970ce16ec 100644 --- a/packages/designer/src/plugin/plugin-manager.ts +++ b/packages/designer/src/plugin/plugin-manager.ts @@ -31,7 +31,18 @@ export class LowCodePluginManager implements ILowCodePluginManager { const config = pluginConfigCreator(ctx, pluginOptions); invariant(config.name, `${config.name} required`, config); ctx.setLogger(config); - invariant(!this.pluginsMap.has(config.name), `${config.name} already exists`, this.pluginsMap.get(config.name)); + const allowOverride = options?.override === true; + if (this.pluginsMap.has(config.name)) { + if (!allowOverride) { + throw new Error(`Plugin with name ${config.name} exists`); + } else { + // clear existing plugin + const originalPlugin = this.pluginsMap.get(config.name); + logger.log('plugin override, originalPlugin with name ', config.name, ' will be destroyed, config:', originalPlugin?.config); + originalPlugin?.destroy(); + this.pluginsMap.delete(config.name); + } + } const plugin = new LowCodePlugin(this, config, pluginOptions); if (options?.autoInit) { await plugin.init(); diff --git a/packages/designer/src/plugin/plugin-types.ts b/packages/designer/src/plugin/plugin-types.ts index f42c5b9a0..cf76d7b38 100644 --- a/packages/designer/src/plugin/plugin-types.ts +++ b/packages/designer/src/plugin/plugin-types.ts @@ -79,4 +79,6 @@ export type ILowCodePluginManager = ILowCodePluginManagerCore & ILowCodePluginMa export type LowCodeRegisterOptions = { autoInit?: boolean; + // allow overriding existing plugin with same name when override === true + override?: boolean; }; diff --git a/packages/designer/tests/plugin/plugin-manager.test.ts b/packages/designer/tests/plugin/plugin-manager.test.ts index e08f8fc4b..cf6a1a720 100644 --- a/packages/designer/tests/plugin/plugin-manager.test.ts +++ b/packages/designer/tests/plugin/plugin-manager.test.ts @@ -136,6 +136,51 @@ describe('plugin 测试', () => { expect(mockFn).toHaveBeenCalledTimes(2); }); + it('默认情况不允许重复注册', async () => { + const mockFn = jest.fn(); + const mockPlugin = (ctx: ILowCodePluginContext, options: any) => { + return { + name: 'demoDuplicated', + init: mockFn, + }; + }; + pluginManager.register(mockPlugin, { test: 1 }); + pluginManager.register(mockPlugin, { test: 1 }).catch(e => { + expect(e).toEqual(new Error('Plugin with name demoDuplicated exists')); + }); + await pluginManager.init(); + }); + + it('插件增加 override 参数时可以重复注册', async () => { + const mockFn = jest.fn(); + const mockPlugin = (ctx: ILowCodePluginContext, options: any) => { + return { + name: 'demoOverride', + init: mockFn, + }; + }; + pluginManager.register(mockPlugin, { test: 1 }); + pluginManager.register(mockPlugin, { test: 1 }, { override: true }); + await pluginManager.init(); + }); + + it('插件增加 override 参数时可以重复注册, 被覆盖的如果已初始化,会被销毁', async () => { + const mockInitFn = jest.fn(); + const mockDestroyFn = jest.fn(); + const mockPlugin = (ctx: ILowCodePluginContext, options: any) => { + return { + name: 'demoOverride', + init: mockInitFn, + destroy: mockDestroyFn, + }; + }; + await pluginManager.register(mockPlugin, { test: 1 }, { autoInit: true }); + expect(mockInitFn).toHaveBeenCalledTimes(1); + await pluginManager.register(mockPlugin, { test: 1 }, { override: true }); + expect(mockDestroyFn).toHaveBeenCalledTimes(1); + await pluginManager.init(); + }); + it('内部事件机制', async () => { const mockFn = jest.fn(); pluginManager.register((ctx: ILowCodePluginContext, options: any) => {