diff --git a/web/src/app.tsx b/web/src/app.tsx index 6db41b863..8bd234a0e 100644 --- a/web/src/app.tsx +++ b/web/src/app.tsx @@ -73,6 +73,7 @@ if (process.env.NODE_ENV === 'development') { trackAllPureComponents: true, trackExtraHooks: [], logOnDifferentValues: true, + exclude: [/^RouterProvider$/], }); }, ); @@ -150,6 +151,13 @@ const RootProvider = ({ children }: React.PropsWithChildren) => { ); }; +const RouterProviderWrapper: React.FC<{ router: typeof routers }> = ({ + router, +}) => { + return ; +}; +RouterProviderWrapper.whyDidYouRender = false; + export default function AppContainer() { // const [router, setRouter] = useState(null); @@ -163,8 +171,7 @@ export default function AppContainer() { return ( - - {/* */} + ); } diff --git a/web/src/routes.tsx b/web/src/routes.tsx index 2858f0567..9c228a8f5 100644 --- a/web/src/routes.tsx +++ b/web/src/routes.tsx @@ -1,4 +1,4 @@ -import { lazy } from 'react'; +import { lazy, Suspense } from 'react'; import { createBrowserRouter, Navigate, type RouteObject } from 'react-router'; import FallbackComponent from './components/fallback-component'; import { IS_ENTERPRISE } from './pages/admin/utils'; @@ -66,252 +66,253 @@ export enum Routes { AdminMonitoring = `${Admin}/monitoring`, } -const routeConfig = [ +const defaultRouteFallback = ( +
+
+
+); + +type LazyRouteConfig = Omit & { + Component?: () => Promise<{ default: React.ComponentType }>; + children?: LazyRouteConfig[]; +}; + +const withLazyRoute = ( + importer: () => Promise<{ default: React.ComponentType }>, + fallback: React.ReactNode = defaultRouteFallback, +) => { + const LazyComponent = lazy(importer); + const Wrapped: React.FC = (props) => ( + + + + ); + Wrapped.displayName = `LazyRoute(${ + (LazyComponent as unknown as React.ComponentType).displayName || + LazyComponent.name || + 'Component' + })`; + return Wrapped; +}; + +const routeConfigOptions = [ { path: '/login', - Component: lazy(() => import('@/pages/login-next')), + Component: () => import('@/pages/login-next'), layout: false, - errorElement: , }, { path: '/login-next', - Component: lazy(() => import('@/pages/login-next')), + Component: () => import('@/pages/login-next'), layout: false, - errorElement: , }, { path: Routes.ChatShare, - Component: lazy(() => import('@/pages/next-chats/share')), + Component: () => import('@/pages/next-chats/share'), layout: false, - errorElement: , }, { path: Routes.AgentShare, - Component: lazy(() => import('@/pages/agent/share')), + Component: () => import('@/pages/agent/share'), layout: false, - errorElement: , }, { path: Routes.ChatWidget, - Component: lazy(() => import('@/pages/next-chats/widget')), + Component: () => import('@/pages/next-chats/widget'), layout: false, - errorElement: , }, { path: Routes.AgentList, - Component: lazy(() => import('@/pages/agents')), - errorElement: , + Component: () => import('@/pages/agents'), }, { path: '/document/:id', - Component: lazy(() => import('@/pages/document-viewer')), + Component: () => import('@/pages/document-viewer'), layout: false, - errorElement: , }, { path: '/*', - Component: lazy(() => import('@/pages/404')), + Component: () => import('@/pages/404'), layout: false, - errorElement: , }, { path: Routes.Root, layout: false, - Component: lazy(() => import('@/layouts/next')), + Component: () => import('@/layouts/next'), wrappers: ['@/wrappers/auth'], children: [ { path: Routes.Root, - Component: lazy(() => import('@/pages/home')), + Component: () => import('@/pages/home'), }, ], - errorElement: , }, { path: Routes.Datasets, layout: false, - Component: lazy(() => import('@/layouts/next')), + Component: () => import('@/layouts/next'), children: [ { path: Routes.Datasets, - Component: lazy(() => import('@/pages/datasets')), + Component: () => import('@/pages/datasets'), }, ], - errorElement: , }, { path: Routes.Chats, layout: false, - Component: lazy(() => import('@/layouts/next')), + Component: () => import('@/layouts/next'), children: [ { path: Routes.Chats, - Component: lazy(() => import('@/pages/next-chats')), + Component: () => import('@/pages/next-chats'), }, ], - errorElement: , }, { path: Routes.Chat + '/:id', layout: false, - Component: lazy(() => import('@/pages/next-chats/chat')), - errorElement: , + Component: () => import('@/pages/next-chats/chat'), }, { path: Routes.Searches, layout: false, - Component: lazy(() => import('@/layouts/next')), + Component: () => import('@/layouts/next'), children: [ { path: Routes.Searches, - Component: lazy(() => import('@/pages/next-searches')), + Component: () => import('@/pages/next-searches'), }, ], - errorElement: , }, { path: Routes.Memories, layout: false, - Component: lazy(() => import('@/layouts/next')), + Component: () => import('@/layouts/next'), children: [ { path: Routes.Memories, - Component: lazy(() => import('@/pages/memories')), + Component: () => import('@/pages/memories'), }, ], - errorElement: , }, { path: `${Routes.Memory}`, layout: false, - Component: lazy(() => import('@/layouts/next')), + Component: () => import('@/layouts/next'), children: [ { path: `${Routes.Memory}`, layout: false, - Component: lazy(() => import('@/pages/memory')), + Component: () => import('@/pages/memory'), children: [ { path: `${Routes.Memory}/${Routes.MemoryMessage}/:id`, - Component: lazy(() => import('@/pages/memory/memory-message')), + Component: () => import('@/pages/memory/memory-message'), }, { path: `${Routes.Memory}/${Routes.MemorySetting}/:id`, - Component: lazy(() => import('@/pages/memory/memory-setting')), + Component: () => import('@/pages/memory/memory-setting'), }, ], }, ], - errorElement: , }, { path: `${Routes.Search}/:id`, layout: false, - Component: lazy(() => import('@/pages/next-search')), - errorElement: , + Component: () => import('@/pages/next-search'), }, { path: `${Routes.SearchShare}`, layout: false, - Component: lazy(() => import('@/pages/next-search/share')), - errorElement: , + Component: () => import('@/pages/next-search/share'), }, { path: Routes.Agents, layout: false, - Component: lazy(() => import('@/layouts/next')), + Component: () => import('@/layouts/next'), children: [ { path: Routes.Agents, - Component: lazy(() => import('@/pages/agents')), + Component: () => import('@/pages/agents'), }, ], - errorElement: , }, { path: `${Routes.AgentLogPage}/:id`, layout: false, - Component: lazy(() => import('@/pages/agents/agent-log-page')), - errorElement: , + Component: () => import('@/pages/agents/agent-log-page'), }, { path: `${Routes.Agent}/:id`, layout: false, - Component: lazy(() => import('@/pages/agent')), - errorElement: , + Component: () => import('@/pages/agent'), }, { path: Routes.AgentTemplates, layout: false, - Component: lazy(() => import('@/pages/agents/agent-templates')), - errorElement: , + Component: () => import('@/pages/agents/agent-templates'), }, { path: Routes.Files, layout: false, - Component: lazy(() => import('@/layouts/next')), + Component: () => import('@/layouts/next'), children: [ { path: Routes.Files, - Component: lazy(() => import('@/pages/files')), + Component: () => import('@/pages/files'), }, ], - errorElement: , }, { path: Routes.DatasetBase, layout: false, - Component: lazy(() => import('@/layouts/next')), + Component: () => import('@/layouts/next'), children: [ { path: Routes.DatasetBase, element: , }, ], - errorElement: , }, { path: Routes.DatasetBase, layout: false, - Component: lazy(() => import('@/pages/dataset')), + Component: () => import('@/pages/dataset'), children: [ { path: `${Routes.Dataset}/:id`, - Component: lazy(() => import('@/pages/dataset/dataset')), + Component: () => import('@/pages/dataset/dataset'), }, { path: `${Routes.DatasetBase}${Routes.DatasetTesting}/:id`, - Component: lazy(() => import('@/pages/dataset/testing')), + Component: () => import('@/pages/dataset/testing'), }, { path: `${Routes.DatasetBase}${Routes.KnowledgeGraph}/:id`, - Component: lazy(() => import('@/pages/dataset/knowledge-graph')), + Component: () => import('@/pages/dataset/knowledge-graph'), }, { path: `${Routes.DatasetBase}${Routes.DataSetOverview}/:id`, - Component: lazy(() => import('@/pages/dataset/dataset-overview')), + Component: () => import('@/pages/dataset/dataset-overview'), }, { path: `${Routes.DatasetBase}${Routes.DataSetSetting}/:id`, - Component: lazy(() => import('@/pages/dataset/dataset-setting')), + Component: () => import('@/pages/dataset/dataset-setting'), }, ], - errorElement: , }, { path: `${Routes.DataflowResult}`, layout: false, - Component: lazy(() => import('@/pages/dataflow-result')), - errorElement: , + Component: () => import('@/pages/dataflow-result'), }, { path: `${Routes.ParsedResult}/chunks`, layout: false, - Component: lazy( - () => - import('@/pages/chunk/parsed-result/add-knowledge/components/knowledge-chunk'), - ), - errorElement: , + Component: () => + import('@/pages/chunk/parsed-result/add-knowledge/components/knowledge-chunk'), }, { path: Routes.Chunk, @@ -319,30 +320,28 @@ const routeConfig = [ children: [ { path: Routes.Chunk, - Component: lazy(() => import('@/pages/chunk')), + Component: () => import('@/pages/chunk'), children: [ { path: `${Routes.ChunkResult}/:id`, - Component: lazy(() => import('@/pages/chunk/chunk-result')), + Component: () => import('@/pages/chunk/chunk-result'), }, { path: `${Routes.ResultView}/:id`, - Component: lazy(() => import('@/pages/chunk/result-view')), + Component: () => import('@/pages/chunk/result-view'), }, ], }, ], - errorElement: , }, { path: Routes.Chunk, layout: false, - Component: lazy(() => import('@/pages/chunk')), - errorElement: , + Component: () => import('@/pages/chunk'), }, { path: '/user-setting', - Component: lazy(() => import('@/pages/user-setting')), + Component: () => import('@/pages/user-setting'), layout: false, children: [ { @@ -351,92 +350,87 @@ const routeConfig = [ }, { path: '/user-setting/profile', - Component: lazy(() => import('@/pages/user-setting/profile')), + Component: () => import('@/pages/user-setting/profile'), }, { path: '/user-setting/locale', - Component: lazy(() => import('@/pages/user-setting/setting-locale')), + Component: () => import('@/pages/user-setting/setting-locale'), }, { path: '/user-setting/model', - Component: lazy(() => import('@/pages/user-setting/setting-model')), + Component: () => import('@/pages/user-setting/setting-model'), }, { path: '/user-setting/team', - Component: lazy(() => import('@/pages/user-setting/setting-team')), + Component: () => import('@/pages/user-setting/setting-team'), }, { path: `/user-setting${Routes.Api}`, - Component: lazy(() => import('@/pages/user-setting/setting-api')), + Component: () => import('@/pages/user-setting/setting-api'), }, { path: `/user-setting${Routes.Mcp}`, - Component: lazy(() => import('@/pages/user-setting/mcp')), + Component: () => import('@/pages/user-setting/mcp'), }, { path: `/user-setting${Routes.DataSource}`, - Component: lazy(() => import('@/pages/user-setting/data-source')), + Component: () => import('@/pages/user-setting/data-source'), }, ], - errorElement: , }, { path: `/user-setting${Routes.DataSource}${Routes.DataSourceDetailPage}`, - Component: lazy( - () => import('@/pages/user-setting/data-source/data-source-detail-page'), - ), + Component: () => + import('@/pages/user-setting/data-source/data-source-detail-page'), + layout: false, - errorElement: , }, { path: Routes.Admin, - Component: lazy(() => import('@/pages/admin/layouts/root-layout')), - errorElement: , + Component: () => import('@/pages/admin/layouts/root-layout'), children: [ { path: Routes.Admin, - Component: lazy(() => import('@/pages/admin/login')), + Component: () => import('@/pages/admin/login'), }, { path: Routes.Admin, - Component: lazy( - () => import('@/pages/admin/layouts/authorized-layout'), - ), + Component: () => import('@/pages/admin/layouts/authorized-layout'), + children: [ { path: `${Routes.AdminUserManagement}/:id`, - Component: lazy(() => import('@/pages/admin/user-detail')), + Component: () => import('@/pages/admin/user-detail'), }, { - Component: lazy( - () => import('@/pages/admin/layouts/navigation-layout'), - ), + Component: () => import('@/pages/admin/layouts/navigation-layout'), + children: [ { path: Routes.AdminServices, - Component: lazy(() => import('@/pages/admin/service-status')), + Component: () => import('@/pages/admin/service-status'), }, { path: Routes.AdminUserManagement, - Component: lazy(() => import('@/pages/admin/users')), + Component: () => import('@/pages/admin/users'), }, { path: Routes.AdminSandboxSettings, - Component: lazy(() => import('@/pages/admin/sandbox-settings')), + Component: () => import('@/pages/admin/sandbox-settings'), }, ...(IS_ENTERPRISE ? [ { path: Routes.AdminWhitelist, - Component: lazy(() => import('@/pages/admin/whitelist')), + Component: () => import('@/pages/admin/whitelist'), }, { path: Routes.AdminRoles, - Component: lazy(() => import('@/pages/admin/roles')), + Component: () => import('@/pages/admin/roles'), }, { path: Routes.AdminMonitoring, - Component: lazy(() => import('@/pages/admin/monitoring')), + Component: () => import('@/pages/admin/monitoring'), }, ] : []), @@ -445,9 +439,24 @@ const routeConfig = [ ], }, ], - } satisfies RouteObject, + } satisfies LazyRouteConfig, ]; +const wrapRoutes = (routes: LazyRouteConfig[]): RouteObject[] => + routes.map((item) => { + const { Component, children, ...rest } = item; + const next: RouteObject = { ...rest, errorElement: }; + if (Component) { + next.Component = withLazyRoute(Component); + } + if (children) { + next.children = wrapRoutes(children); + } + return next; + }); + +const routeConfig = wrapRoutes(routeConfigOptions); + const routers = createBrowserRouter(routeConfig, { basename: import.meta.env.VITE_BASE_URL || '/', });