From 517036439c4ba179fc992ba0e76aa11280556889 Mon Sep 17 00:00:00 2001 From: yangy Date: Tue, 26 May 2026 19:16:42 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=82=E9=85=8Dx9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/App.tsx | 39 ++++++++++++++--- client/src/components/DesktopAIShell.tsx | 9 +++- client/src/components/PageLoader.tsx | 8 ++++ vite.config.ts | 55 +++++++++--------------- 4 files changed, 69 insertions(+), 42 deletions(-) create mode 100644 client/src/components/PageLoader.tsx diff --git a/client/src/App.tsx b/client/src/App.tsx index ea872bb..0e77e35 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,16 +1,16 @@ +import { lazy, Suspense } from "react"; import { Toaster } from "@/components/ui/sonner"; import { TooltipProvider } from "@/components/ui/tooltip"; import { Route, Switch, Router } from "wouter"; import { useHashLocation } from "wouter/use-hash-location"; import ErrorBoundary from "./components/ErrorBoundary"; +import PageLoader from "./components/PageLoader"; import { ThemeProvider } from "./contexts/ThemeContext"; import { DeviceProvider } from "./contexts/DeviceContext"; import Home from "./pages/Home"; import NotFound from "./pages/NotFound"; import Dashboard from "./pages/Dashboard"; import AudioPage from "./pages/AudioPage"; -import EQPage from "./pages/EQPage"; -import EffectsPage from "./pages/EffectsPage"; import BluetoothPage from "./pages/BluetoothPage"; import DspPage from "./pages/DspPage"; import DisplayPage from "./pages/DisplayPage"; @@ -18,14 +18,41 @@ import SystemPage from "./pages/SystemPage"; import IOPage from "./pages/IOPage"; import VUPage from "./pages/VUPage"; import SelectPage from "./pages/SelectPage"; -import AIPage from "./pages/AIPage"; import CommunityPage from "./pages/CommunityPage"; import { AIDrawerProvider } from "./contexts/AIDrawerContext"; import DesktopAIShell from "./components/DesktopAIShell"; import { appShellColumnClass, appShellGutterClass } from "./lib/appShell"; +const EQPage = lazy(() => import("./pages/EQPage")); +const EffectsPage = lazy(() => import("./pages/EffectsPage")); +const AIPage = lazy(() => import("./pages/AIPage")); + +function LazyRoute({ children }: { children: React.ReactNode }) { + return }>{children}; +} + function AIPageRoute() { - return ; + return ( + + + + ); +} + +function EQPageRoute() { + return ( + + + + ); +} + +function EffectsPageRoute() { + return ( + + + + ); } function AppRouter() { @@ -34,8 +61,8 @@ function AppRouter() { - - + + diff --git a/client/src/components/DesktopAIShell.tsx b/client/src/components/DesktopAIShell.tsx index 94c9def..ca1bc75 100644 --- a/client/src/components/DesktopAIShell.tsx +++ b/client/src/components/DesktopAIShell.tsx @@ -1,4 +1,5 @@ -import AIPage from "@/pages/AIPage"; +import { lazy, Suspense } from "react"; +import PageLoader from "@/components/PageLoader"; import { useAIDrawer } from "@/contexts/AIDrawerContext"; import { useIsLgUp } from "@/hooks/useIsLgUp"; import { cn } from "@/lib/utils"; @@ -11,6 +12,8 @@ import { type RefObject, } from "react"; +const AIPage = lazy(() => import("@/pages/AIPage")); + function SplitDivider({ containerRef, onResize, @@ -114,7 +117,9 @@ export default function DesktopAIShell({ children }: { children: ReactNode }) { className="flex h-full min-h-0 min-w-0 flex-col overflow-hidden border-l border-white/[0.08] bg-[#0d1117]" style={{ flex: `${splitPercent} 1 0%` }} > - setOpen(false)} /> + }> + setOpen(false)} /> + )} diff --git a/client/src/components/PageLoader.tsx b/client/src/components/PageLoader.tsx new file mode 100644 index 0000000..7094528 --- /dev/null +++ b/client/src/components/PageLoader.tsx @@ -0,0 +1,8 @@ +/** Lightweight fallback while lazy-loaded routes fetch their chunks. */ +export default function PageLoader() { + return ( +
+ Loading… +
+ ); +} diff --git a/vite.config.ts b/vite.config.ts index 09abb2f..b582cf5 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -176,7 +176,7 @@ const plugins = [ export default defineConfig({ plugins, - base: process.env.NODE_ENV === "production" ? "/x8/v2/" : "/", + base: process.env.NODE_ENV === "production" ? "/x9/v2/" : "/", resolve: { alias: { "@": path.resolve(import.meta.dirname, "client", "src"), @@ -208,48 +208,35 @@ export default defineConfig({ manualChunks(id) { if (!id.includes("node_modules")) return; - // Keep core runtime dependencies stable for better long-term caching. - if (id.includes("node_modules/react/") || id.includes("node_modules/react-dom/")) { + if ( + id.includes("/echarts/") || + id.includes("/zrender/") || + id.includes("\\echarts\\") || + id.includes("\\zrender\\") + ) { + return "echarts-vendor"; + } + + if (id.includes("/react-dom/") || id.includes("/react/")) { return "react-vendor"; } - if (id.includes("node_modules/wouter/")) { - return "router-vendor"; - } - - // Split large libraries into their own chunks to avoid a single huge entry bundle. - if (id.includes("node_modules/echarts/")) return "echarts-vendor"; - if (id.includes("node_modules/recharts/")) return "recharts-vendor"; - if (id.includes("node_modules/framer-motion/")) return "motion-vendor"; - if (id.includes("node_modules/@radix-ui/")) return "radix-vendor"; - - // Group frequently used small UI helpers. + if (id.includes("/wouter/")) return "router-vendor"; + if (id.includes("/@radix-ui/")) return "radix-vendor"; + if (id.includes("/framer-motion/")) return "motion-vendor"; if ( - id.includes("node_modules/lucide-react/") || - id.includes("node_modules/class-variance-authority/") || - id.includes("node_modules/clsx/") || - id.includes("node_modules/tailwind-merge/") + id.includes("/lucide-react/") || + id.includes("/recharts/") || + id.includes("/class-variance-authority/") || + id.includes("/clsx/") || + id.includes("/tailwind-merge/") ) { return "ui-vendor"; } - - // Fall back to per-package vendor chunks. - const packageMatch = id.match( - /node_modules[\\/](?:\.pnpm[\\/][^\\/]+[\\/]node_modules[\\/])?(@?[^\\/]+(?:[\\/][^\\/]+)?)/, - ); - const packagePath = packageMatch?.[1]; - if (!packagePath) return "vendor"; - - const packageName = packagePath.startsWith("@") - ? packagePath.split(/[\\/]/).slice(0, 2).join("_") - : packagePath.split(/[\\/]/)[0]; - - return `vendor-${packageName}`; }, - // Prevent Rollup from merging manual chunks back into larger bundles. - onlyExplicitManualChunks: true, }, }, - chunkSizeWarningLimit: 500, + // echarts full build is ~1.1 MB; only loaded on /eq and /effects (lazy routes). + chunkSizeWarningLimit: 1200, cssCodeSplit: true, }, server: {