This is an automated email from the ASF dual-hosted git repository.

robin0716 pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/incubator-answer.git

commit 8753716ceb789d59effc5c3613d0215775c225ec
Author: robin <[email protected]>
AuthorDate: Mon Oct 21 16:19:32 2024 +0800

    refactor(ui): optimize initial loading and extract event logic of plugin 
kit out
---
 ui/src/App.tsx                    | 33 ++++--------------------------
 ui/src/router/index.tsx           | 22 +++++++++++++-------
 ui/src/utils/pluginKit/emitter.ts | 34 -------------------------------
 ui/src/utils/pluginKit/index.ts   | 42 +++++++++++----------------------------
 4 files changed, 31 insertions(+), 100 deletions(-)

diff --git a/ui/src/App.tsx b/ui/src/App.tsx
index f799042a..8c425f29 100644
--- a/ui/src/App.tsx
+++ b/ui/src/App.tsx
@@ -17,44 +17,19 @@
  * under the License.
  */
 
-import {
-  type RouteObject,
-  RouterProvider,
-  createBrowserRouter,
-} from 'react-router-dom';
-import { useState, useEffect } from 'react';
+import { RouterProvider, createBrowserRouter } from 'react-router-dom';
 
 import './i18n/init';
 
-import { subscribe, unsubscribe } from '@/utils/pluginKit';
-import resolveRoutes from '@/router';
+import '@/utils/pluginKit';
+import { useMergeRoutes } from '@/router';
 import InitialLoadingPlaceholder from '@/components/InitialLoadingPlaceholder';
 
-function useResolvedRoutes() {
-  const [routes, setRoutes] = useState<RouteObject[]>([]);
-
-  useEffect(() => {
-    const callback = () => {
-      setRoutes(resolveRoutes());
-    };
-
-    subscribe('registered', callback);
-
-    return () => {
-      unsubscribe('registered', callback);
-    };
-  }, []);
-
-  return routes;
-}
-
 function App() {
-  const routes = useResolvedRoutes();
-
+  const routes = useMergeRoutes();
   if (routes.length === 0) {
     return <InitialLoadingPlaceholder />;
   }
-
   const router = createBrowserRouter(routes, {
     basename: process.env.REACT_APP_BASE_URL,
   });
diff --git a/ui/src/router/index.tsx b/ui/src/router/index.tsx
index 8c111e0f..ea2fdf3c 100644
--- a/ui/src/router/index.tsx
+++ b/ui/src/router/index.tsx
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-import { Suspense, lazy } from 'react';
+import { Suspense, lazy, useEffect, useState } from 'react';
 import { RouteObject } from 'react-router-dom';
 
 import Layout from '@/pages/Layout';
@@ -75,13 +75,21 @@ const routeWrapper = (routeNodes: RouteNode[], root: 
RouteNode[]) => {
   });
 };
 
-function resolveRoutes(): RouteObject[] {
-  const routes: RouteNode[] = [];
-  const mergedRoutes = mergeRoutePlugins(baseRoutes);
+function useMergeRoutes() {
+  const [routesState, setRoutes] = useState<RouteObject[]>([]);
 
-  routeWrapper(mergedRoutes, routes);
+  const init = async () => {
+    const routes = [];
+    const mergedRoutes = await mergeRoutePlugins(baseRoutes).catch(() => []);
+    routeWrapper(mergedRoutes, routes);
+    setRoutes(routes);
+  };
 
-  return routes as RouteObject[];
+  useEffect(() => {
+    init();
+  }, []);
+
+  return routesState;
 }
 
-export default resolveRoutes;
+export { useMergeRoutes };
diff --git a/ui/src/utils/pluginKit/emitter.ts 
b/ui/src/utils/pluginKit/emitter.ts
deleted file mode 100644
index eee427b6..00000000
--- a/ui/src/utils/pluginKit/emitter.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-type EventName = string;
-type EventHandler = () => void;
-
-class SimpleEventEmitter {
-  events: Record<EventName, EventHandler[]> = {};
-
-  on(name: EventName, handler: EventHandler) {
-    if (!this.events[name]) {
-      this.events[name] = [];
-    }
-
-    this.events[name].push(handler);
-  }
-
-  off(name: EventName, handler?: EventHandler) {
-    const handlers = this.events[name];
-
-    if (!handlers || handlers.length === 0) {
-      return;
-    }
-
-    if (handler) {
-      this.events[name] = handlers.filter((func) => func !== handler);
-    } else {
-      delete this.events[name];
-    }
-  }
-
-  emit(name: EventName) {
-    (this.events[name] || []).forEach((handler) => handler());
-  }
-}
-
-export default SimpleEventEmitter;
diff --git a/ui/src/utils/pluginKit/index.ts b/ui/src/utils/pluginKit/index.ts
index 39d1edb5..346c1456 100644
--- a/ui/src/utils/pluginKit/index.ts
+++ b/ui/src/utils/pluginKit/index.ts
@@ -29,7 +29,6 @@ import request from '@/utils/request';
 
 import { initI18nResource } from './utils';
 import { Plugin, PluginInfo, PluginType } from './interface';
-import SimpleEventEmitter from './emitter';
 
 /**
  * This information is to be defined for all components.
@@ -43,23 +42,23 @@ import SimpleEventEmitter from './emitter';
  * @field description: Plugin description, optionally configurable. Usually 
read from the `i18n` file
  */
 
-class Plugins extends SimpleEventEmitter {
+class Plugins {
   plugins: Plugin[] = [];
 
   registeredPlugins: Type.ActivatedPlugin[] = [];
 
+  initialization: Promise<void>;
+
   constructor() {
-    super();
-    this.init();
+    this.initialization = this.init();
   }
 
-  init() {
+  async init() {
     this.registerBuiltin();
 
-    getPluginsStatus().then((plugins) => {
-      this.registeredPlugins = plugins.filter((p) => p.enabled);
-      this.registerPlugins();
-    });
+    const plugins = await getPluginsStatus().catch(() => []);
+    this.registeredPlugins = plugins.filter((p) => p.enabled);
+    await this.registerPlugins();
   }
 
   refresh() {
@@ -105,7 +104,6 @@ class Plugins extends SimpleEventEmitter {
       .filter((p) => p);
     return Promise.all(plugins.map((p) => p())).then((resolvedPlugins) => {
       resolvedPlugins.forEach((plugin) => this.register(plugin));
-      this.emit('registered');
       return true;
     });
   }
@@ -122,18 +120,6 @@ class Plugins extends SimpleEventEmitter {
     this.plugins.push(plugin);
   }
 
-  activatePlugins(activatedPlugins: Type.ActivatedPlugin[]) {
-    this.plugins.forEach((plugin: any) => {
-      const { slug_name } = plugin.info;
-      const activatedPlugin: any = activatedPlugins?.find(
-        (p) => p.slug_name === slug_name,
-      );
-      if (activatedPlugin) {
-        plugin.activated = activatedPlugin?.enabled;
-      }
-    });
-  }
-
   getPlugin(slug_name: string) {
     return this.plugins.find((p) => p.info.slug_name === slug_name);
   }
@@ -150,10 +136,8 @@ class Plugins extends SimpleEventEmitter {
 
 const plugins = new Plugins();
 
-const subscribe = plugins.on.bind(plugins);
-const unsubscribe = plugins.off.bind(plugins);
-
-const getRoutePlugins = () => {
+const getRoutePlugins = async () => {
+  await plugins.initialization;
   return plugins
     .getPlugins()
     .filter((plugin) => plugin.info.type === PluginType.Route);
@@ -183,8 +167,8 @@ const validateRoutePlugin = async (slugName) => {
   return Boolean(registeredPlugin?.enabled);
 };
 
-const mergeRoutePlugins = (routes) => {
-  const routePlugins = getRoutePlugins();
+const mergeRoutePlugins = async (routes) => {
+  const routePlugins = await getRoutePlugins();
   if (routePlugins.length === 0) {
     return routes;
   }
@@ -290,7 +274,5 @@ export {
   useCaptchaPlugin,
   useRenderPlugin,
   PluginType,
-  subscribe,
-  unsubscribe,
 };
 export default plugins;

Reply via email to