From 34fee12496a7e2d886087f0a19be2510de934b92 Mon Sep 17 00:00:00 2001 From: Tunglies <77394545+Tunglies@users.noreply.github.com> Date: Sat, 11 Jul 2026 18:01:53 +0800 Subject: [PATCH] fix(frontend): warm lazy routes concurrently after idle Start all navigation route preloads after a single idle gate and show centered loading fallbacks during cold route loads. --- src/pages/_layout.tsx | 22 ++++++++++++----- src/pages/_routers.tsx | 55 ++++++++++++++++++++---------------------- 2 files changed, 42 insertions(+), 35 deletions(-) diff --git a/src/pages/_layout.tsx b/src/pages/_layout.tsx index 4266eafc8..fdf498d8a 100644 --- a/src/pages/_layout.tsx +++ b/src/pages/_layout.tsx @@ -39,7 +39,7 @@ import { Outlet, useLocation, useNavigate } from 'react-router' import iconDark from '@/assets/image/icon_dark.svg?react' import iconLight from '@/assets/image/icon_light.svg?react' import LogoSvg from '@/assets/image/logo.svg?react' -import { BaseErrorBoundary } from '@/components/base' +import { BaseErrorBoundary, BaseLoading } from '@/components/base' import { LayoutItem } from '@/components/layout/layout-item' import { LayoutTraffic } from '@/components/layout/layout-traffic' import { NoticeManager } from '@/components/layout/notice-manager' @@ -240,13 +240,10 @@ const Layout = () => { } const controller = new AbortController() - const timerId = window.setTimeout(() => { - void preloadNavigationRoutes(controller.signal) - }, 2000) + void preloadNavigationRoutes(controller.signal) return () => { controller.abort() - window.clearTimeout(timerId) } }, [themeReady, pageVisible]) @@ -501,7 +498,20 @@ const Layout = () => { bottom: 0, }} > - + + + + } + > diff --git a/src/pages/_routers.tsx b/src/pages/_routers.tsx index f38d8c52f..3bbd9de33 100644 --- a/src/pages/_routers.tsx +++ b/src/pages/_routers.tsx @@ -6,6 +6,7 @@ import LockOpenRoundedIcon from '@mui/icons-material/LockOpenRounded' import SettingsRoundedIcon from '@mui/icons-material/SettingsRounded' import SubjectRoundedIcon from '@mui/icons-material/SubjectRounded' import WifiRoundedIcon from '@mui/icons-material/WifiRounded' +import { Box } from '@mui/material' import { lazy, Suspense, type ComponentType } from 'react' import { createBrowserRouter, RouteObject } from 'react-router' @@ -17,6 +18,7 @@ import ProxiesSvg from '@/assets/image/itemicon/proxies.svg?react' import RulesSvg from '@/assets/image/itemicon/rules.svg?react' import SettingsSvg from '@/assets/image/itemicon/settings.svg?react' import UnlockSvg from '@/assets/image/itemicon/unlock.svg?react' +import { BaseLoading } from '@/components/base' import { ensureLanguageSections } from '@/services/i18n' import Layout from './_layout' @@ -91,7 +93,20 @@ const createLazyRoute = ( const preload = createRoutePreload(load, sections) const Component = lazy(preload) const LazyRoute = () => ( - + + + + } + > ) @@ -156,36 +171,18 @@ export const navItems = [ }, ] -const navigationWarmupPriority = ['/connections', '/logs', '/rules'] - -const navigationWarmupItems = [...navItems].sort((left, right) => { - const leftIndex = navigationWarmupPriority.indexOf(left.path) - const rightIndex = navigationWarmupPriority.indexOf(right.path) - const leftRank = - leftIndex === -1 ? navigationWarmupPriority.length : leftIndex - const rightRank = - rightIndex === -1 ? navigationWarmupPriority.length : rightIndex - - return leftRank - rightRank -}) - export const preloadNavigationRoutes = async (signal: AbortSignal) => { - for (const item of navigationWarmupItems) { - if (signal.aborted) { - return - } - const preload = 'preload' in item ? item.preload : undefined - if (!preload) { - continue - } - - await waitForWarmupIdle(signal) - if (signal.aborted) { - return - } - - await preload().catch(() => {}) + await waitForWarmupIdle(signal) + if (signal.aborted) { + return } + + await Promise.all( + navItems.map((item) => { + const preload = 'preload' in item ? item.preload : undefined + return preload?.().catch(() => {}) + }), + ) } export const router = createBrowserRouter([