This commit is contained in:
yangy
2026-05-26 19:16:42 +08:00
parent 47ea7d7b56
commit 517036439c
4 changed files with 69 additions and 42 deletions
+33 -6
View File
@@ -1,16 +1,16 @@
import { lazy, Suspense } from "react";
import { Toaster } from "@/components/ui/sonner"; import { Toaster } from "@/components/ui/sonner";
import { TooltipProvider } from "@/components/ui/tooltip"; import { TooltipProvider } from "@/components/ui/tooltip";
import { Route, Switch, Router } from "wouter"; import { Route, Switch, Router } from "wouter";
import { useHashLocation } from "wouter/use-hash-location"; import { useHashLocation } from "wouter/use-hash-location";
import ErrorBoundary from "./components/ErrorBoundary"; import ErrorBoundary from "./components/ErrorBoundary";
import PageLoader from "./components/PageLoader";
import { ThemeProvider } from "./contexts/ThemeContext"; import { ThemeProvider } from "./contexts/ThemeContext";
import { DeviceProvider } from "./contexts/DeviceContext"; import { DeviceProvider } from "./contexts/DeviceContext";
import Home from "./pages/Home"; import Home from "./pages/Home";
import NotFound from "./pages/NotFound"; import NotFound from "./pages/NotFound";
import Dashboard from "./pages/Dashboard"; import Dashboard from "./pages/Dashboard";
import AudioPage from "./pages/AudioPage"; import AudioPage from "./pages/AudioPage";
import EQPage from "./pages/EQPage";
import EffectsPage from "./pages/EffectsPage";
import BluetoothPage from "./pages/BluetoothPage"; import BluetoothPage from "./pages/BluetoothPage";
import DspPage from "./pages/DspPage"; import DspPage from "./pages/DspPage";
import DisplayPage from "./pages/DisplayPage"; import DisplayPage from "./pages/DisplayPage";
@@ -18,14 +18,41 @@ import SystemPage from "./pages/SystemPage";
import IOPage from "./pages/IOPage"; import IOPage from "./pages/IOPage";
import VUPage from "./pages/VUPage"; import VUPage from "./pages/VUPage";
import SelectPage from "./pages/SelectPage"; import SelectPage from "./pages/SelectPage";
import AIPage from "./pages/AIPage";
import CommunityPage from "./pages/CommunityPage"; import CommunityPage from "./pages/CommunityPage";
import { AIDrawerProvider } from "./contexts/AIDrawerContext"; import { AIDrawerProvider } from "./contexts/AIDrawerContext";
import DesktopAIShell from "./components/DesktopAIShell"; import DesktopAIShell from "./components/DesktopAIShell";
import { appShellColumnClass, appShellGutterClass } from "./lib/appShell"; 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 <Suspense fallback={<PageLoader />}>{children}</Suspense>;
}
function AIPageRoute() { function AIPageRoute() {
return <AIPage />; return (
<LazyRoute>
<AIPage />
</LazyRoute>
);
}
function EQPageRoute() {
return (
<LazyRoute>
<EQPage />
</LazyRoute>
);
}
function EffectsPageRoute() {
return (
<LazyRoute>
<EffectsPage />
</LazyRoute>
);
} }
function AppRouter() { function AppRouter() {
@@ -34,8 +61,8 @@ function AppRouter() {
<Route path="/" component={Home} /> <Route path="/" component={Home} />
<Route path="/dashboard" component={Dashboard} /> <Route path="/dashboard" component={Dashboard} />
<Route path="/audio" component={AudioPage} /> <Route path="/audio" component={AudioPage} />
<Route path="/eq" component={EQPage} /> <Route path="/eq" component={EQPageRoute} />
<Route path="/effects" component={EffectsPage} /> <Route path="/effects" component={EffectsPageRoute} />
<Route path="/bluetooth" component={BluetoothPage} /> <Route path="/bluetooth" component={BluetoothPage} />
<Route path="/dsp" component={DspPage} /> <Route path="/dsp" component={DspPage} />
<Route path="/display" component={DisplayPage} /> <Route path="/display" component={DisplayPage} />
+7 -2
View File
@@ -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 { useAIDrawer } from "@/contexts/AIDrawerContext";
import { useIsLgUp } from "@/hooks/useIsLgUp"; import { useIsLgUp } from "@/hooks/useIsLgUp";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
@@ -11,6 +12,8 @@ import {
type RefObject, type RefObject,
} from "react"; } from "react";
const AIPage = lazy(() => import("@/pages/AIPage"));
function SplitDivider({ function SplitDivider({
containerRef, containerRef,
onResize, 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]" 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%` }} style={{ flex: `${splitPercent} 1 0%` }}
> >
<AIPage variant="split" onClose={() => setOpen(false)} /> <Suspense fallback={<PageLoader />}>
<AIPage variant="split" onClose={() => setOpen(false)} />
</Suspense>
</div> </div>
</> </>
)} )}
+8
View File
@@ -0,0 +1,8 @@
/** Lightweight fallback while lazy-loaded routes fetch their chunks. */
export default function PageLoader() {
return (
<div className="flex min-h-[40vh] items-center justify-center">
<span className="text-sm text-white/40">Loading</span>
</div>
);
}
+21 -34
View File
@@ -176,7 +176,7 @@ const plugins = [
export default defineConfig({ export default defineConfig({
plugins, plugins,
base: process.env.NODE_ENV === "production" ? "/x8/v2/" : "/", base: process.env.NODE_ENV === "production" ? "/x9/v2/" : "/",
resolve: { resolve: {
alias: { alias: {
"@": path.resolve(import.meta.dirname, "client", "src"), "@": path.resolve(import.meta.dirname, "client", "src"),
@@ -208,48 +208,35 @@ export default defineConfig({
manualChunks(id) { manualChunks(id) {
if (!id.includes("node_modules")) return; if (!id.includes("node_modules")) return;
// Keep core runtime dependencies stable for better long-term caching. if (
if (id.includes("node_modules/react/") || id.includes("node_modules/react-dom/")) { 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"; return "react-vendor";
} }
if (id.includes("node_modules/wouter/")) { if (id.includes("/wouter/")) return "router-vendor";
return "router-vendor"; if (id.includes("/@radix-ui/")) return "radix-vendor";
} if (id.includes("/framer-motion/")) return "motion-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 ( if (
id.includes("node_modules/lucide-react/") || id.includes("/lucide-react/") ||
id.includes("node_modules/class-variance-authority/") || id.includes("/recharts/") ||
id.includes("node_modules/clsx/") || id.includes("/class-variance-authority/") ||
id.includes("node_modules/tailwind-merge/") id.includes("/clsx/") ||
id.includes("/tailwind-merge/")
) { ) {
return "ui-vendor"; 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, cssCodeSplit: true,
}, },
server: { server: {