import { useEffect, useState } from "react"; import { useGlobalContext } from "@common/contexts/GlobalStateContext"; import { DEFAULT_LOCAL_PLUGIN_PATH, generateRemoteModuleTemplate, loadRemoteModule, validateExportLifecycle } from "@common/utils/plugin.tsx"; import { useFetch } from "@common/hooks/http"; import { PluginConfigType, RouteConfig } from "@common/const/type.ts"; import { ApiparkPluginDriverType ,RouterMapConfig} from "@common/const/type"; import { usePluginEventHub } from "@common/contexts/PluginEventHubContext"; import { usePluginSlotHub } from "@common/contexts/PluginSlotHubContext"; import { App } from "antd"; const mockData = { buildAt:'2024-09-13T03:51:25Z', build_user:'gitlab-runner', git_commint:'6438d5aaff146dc560ed0d8563788e64a49640a5', goversion:'go version go1.21.4 linux/amd64', guide:true, plugins:[ { driver:'apipark.builtIn.component', name:'guide', router:[ { path:'guide/*', type:'normal' } ] }, { driver:'apipark.builtIn.component', name:'team', router:[ { path:'team', type:'normal' } ] }, { driver:'apipark.builtIn.component', name:'service', router:[ { path:'service', type:'normal' } ] }, { driver:'apipark.builtIn.component', name:'datasourcing', router:[ { path:'datasourcing', type:'normal' } ] }, { driver:'apipark.builtIn.component', name:'cluster', router:[ { path:'cluster', type:'normal' } ] }, { driver:'apipark.builtIn.component', name:'aisetting', router:[ { path:'aisetting', type:'normal' } ] }, { driver:'apipark.builtIn.component', name:'cert', router:[ { path:'cert', type:'normal' } ] }, { driver:'apipark.builtIn.component', name:'serviceHub', router:[ { path:'serviceHub', type:'normal' } ] }, { driver:'apipark.builtIn.component', name:'commonsetting', router:[ { path:'commonsetting', type:'normal' } ] }, { driver:'apipark.builtIn.component', name:'consumer', router:[ { path:'consumer', type:'normal' } ] }, { driver:'apipark.builtIn.component', name:'member', router:[ { path:'member', type:'normal' } ] }, { driver:'apipark.builtIn.component', name:'role', router:[ { path:'role', type:'normal' } ] }, { driver:'apipark.builtIn.component', name:'analytics', router:[ { path:'analytics', type:'normal' } ] }, { driver:'apipark.builtIn.component', name:'template', router:[ { path:'template/:moduleId', type:'normal' } ] }, { driver:'apipark.builtIn.component', name:'logsettings', router:[ { path:'logsettings/*', type:'normal' } ] }, { driver:'apipark.builtIn.component', name:'resourcesettings', router:[ { path:'resourcesettings/*', type:'normal' } ] }, { driver:'apipark.builtIn.component', name:'userProfile', router:[ { path:'userProfile', type:'normal' } ] }, { driver:'apipark.builtIn.component', name:'globalPolicy', router:[ { path:'globalPolicy', type:'normal' } ] }, // { // "driver": "apipark.remote.normal", // "name": "remote", // "router": [ // { // "path": "remote", // "type": "normal" // } // ] // }, // { // "driver": "apipark.local.preload", // "name": "auth", // "router": [ // { // "expose": "AppModule", // "path": "auth", // "type": "root" // }, // { // "expose": "AuthInfoModule", // "path": "auth-info", // "type": "normal" // } // ] // }, // { // "driver": "apipark.builtIn.component", // "name": "email", // "router": [ // { // "path": "system/email", // "type": "normal" // } // ] // }, // { // "driver": "apipark.builtIn.module", // "name": "open-api", // "router": [ // { // "path": "system/ext-app", // "type": "normal" // } // ] // }, // { // "driver": "apipark.local.preload", // "name": "remote", // "router": [ // { // "expose": "App", // "path": "router1/*", // "type": "normal" // } // ] // }, // { // "driver": "apipark.remote.normal", // "name": "apispace", // "router": [ // { // "path": "remote/apispace", // "type": "normal" // } // ] // } ], powered:'Powered by https://eolink.com', product:'apipark', version:'6438d5aa' } export type ExecutePluginType = PluginConfigType & { expose:string, bootstrap:string } const usePluginLoader = (apipark:ApiparkPluginDriverType,routerMap:Map) => { const [modules, setModules] = useState(new Map()); const [executeList, setExecuteList] = useState([]); const [baseHref, setBaseHref] = useState(''); const [pendingTasks, setPendingTasks] = useState(0); const {fetchData} = useFetch(); const pluginProvider = useGlobalContext(); const pluginEventHub = usePluginEventHub(); const pluginSlotHub = usePluginSlotHub(); const { getMenuList,dispatch} = pluginProvider const { modal,message } = App.useApp() const [startLoadExecutePlugin, setStartLoadExecutePlugin] = useState(false) const messageService = message; const modalService = modal; let startInstallPlugin = false useEffect(()=>{ if (startLoadExecutePlugin && pendingTasks === 0 && executeList.length > 0) { loadExecutedPlugin(); } },[pendingTasks, executeList]) const getModule = (routerPrefix:string, specific = false) => { if (routerPrefix.startsWith('/')) { routerPrefix = routerPrefix.substring(1); } if (specific) { return modules.get(routerPrefix); } let matchedModule = null; let matchedLength = 0; modules.forEach((value, key) => { if (routerPrefix.startsWith(key) && key.length > matchedLength) { matchedModule = value; matchedLength = key.length; } }); return matchedModule; }; const loadModule = async (routerPrefix: string, pluginName: any, exposedModule: string , pluginPath: any) => { if (!modules.get(routerPrefix)) { try { const loadedModule = await loadRemoteModule(generateRemoteModuleTemplate(pluginName, exposedModule, pluginPath)); const Module = loadedModule.default ?? loadedModule let ModuleBootstrap; try { ModuleBootstrap = await loadRemoteModule(generateRemoteModuleTemplate(pluginName, 'Bootstrap', pluginPath)); } catch (error) { console.warn('Bootstrap module not found:', error); } setModules(prevModules => new Map(prevModules).set(routerPrefix,Module[exposedModule] )); if (!validateExportLifecycle(Module)) { console.error('需要导出插件生命周期函数'); return; } await Module.bootstrap?.({ pluginProvider, pluginEventHub, pluginSlotHub }); return Module; } catch (error) { console.error('导入插件失败:', error); } } return getModule(routerPrefix, true); }; const loadExecutedPlugin = async () => { setStartLoadExecutePlugin(true) for (const plugin of executeList) { try { const Module = await loadRemoteModule(generateRemoteModuleTemplate(plugin.name, plugin?.expose || 'Bootstrap', plugin.path || `${DEFAULT_LOCAL_PLUGIN_PATH}${plugin.name}/apipark.js`)); const bootstrap = Module.bootstrap; if (!bootstrap) { console.warn('立即执行插件未导出Bootstrap模块或bootstrap函数'); } else { await bootstrap({ pluginEventHub, pluginSlotHub, pluginProvider, platformProvider:null, messageService, modalService, }); } } catch (error) { console.error('执行插件失败:', error); } } }; const loadPlugins = () => { return new Promise((resolve) => { if(startInstallPlugin) { return resolve(true) } startInstallPlugin = true installPlugin().then(async (res)=>{ // reset route after loading executed plugins await loadExecutedPlugin(); return resolve(res) }) }); }; const installPlugin = () => { return new Promise((resolve, reject) => { // fetchData('system/plugins',{method:'GET'}).then((resp) => { // if (resp.code === 0){ const resp = {data:mockData} dispatch({type:'UPDATE_VERSION',version:resp.data.version}) dispatch({type:'UPDATE_DATE',updateDate:resp.data.buildAt}) dispatch({type:'UPDATE_POWER',powered:resp.data.powered}) const driverMethod = { apipark: apipark }; const pluginConfigList = resp.data.plugins; const pluginLoader = { loadModule }; const pluginLifecycleGuard ={}; const builtInPluginLoader = loadBuiltInModule; pluginSlotHub.addSlot('renewMenu', () => { getMenuList() }); for (const plugin of pluginConfigList) { try { const driverName = plugin.driver; if (!driverName) { console.error('no driver name'); continue; } const driver = driverName.split('.').reduce((driverMethod: { [x: string]: any; }, driverName: string | number) => driverMethod[driverName], driverMethod); if(driverName.split('.')[2] === 'preload'){ setPendingTasks(prev => prev + 1); } ;(driver as Function )?.({ setExecuteList:(callback:ExecutePluginType[]) => { setExecuteList(callback); setPendingTasks(prev => prev - 1); }, pluginLoader, pluginProvider, pluginLifecycleGuard, builtInPluginLoader }, plugin); } catch (err) { console.warn('安装插件出错:', err); } } resolve(true); // } else { // messageService.error(resp.msg || '获取插件配置列表失败,请重试!'); // reject(new Error(resp.msg || '获取插件配置列表失败')); // } // }); } ); }; const loadBuiltInModule = (pluginName: any) => { try { const { module } = routerMap.get(pluginName)!; return module; } catch (err) { console.warn(`安装内置插件[${pluginName}]出错:`, err); } }; return { loadPlugins, loadModule, loadExecutedPlugin, setBaseHref, getModule }; }; export default usePluginLoader;