perf(web): lazy-load app routes and heavy surfaces
This commit is contained in:
parent
e853ffc0c5
commit
7de6b236c0
@ -1,10 +1,9 @@
|
|||||||
import { useState, useEffect, useCallback, useRef } from 'react';
|
import { Suspense, lazy, useState, useEffect, useCallback, useRef } from 'react';
|
||||||
import { BrowserRouter } from 'react-router-dom';
|
import { BrowserRouter } from 'react-router-dom';
|
||||||
import { useWebSocket } from './hooks/useWebSocket';
|
import { useWebSocket } from './hooks/useWebSocket';
|
||||||
import { useAuth } from './components/AuthContext';
|
import { useAuth } from './components/AuthContext';
|
||||||
import { Login } from './components/Login';
|
import { Login } from './components/Login';
|
||||||
import { ResetPassword } from './components/ResetPassword';
|
import { ResetPassword } from './components/ResetPassword';
|
||||||
import { ChatControl } from './components/ChatControl';
|
|
||||||
import { AppContext } from './context/AppContext';
|
import { AppContext } from './context/AppContext';
|
||||||
import { AppShell } from './components/layout/AppShell';
|
import { AppShell } from './components/layout/AppShell';
|
||||||
import { useBacktestFeatureGate } from './backtest/useBacktestFeatureGate';
|
import { useBacktestFeatureGate } from './backtest/useBacktestFeatureGate';
|
||||||
@ -12,6 +11,8 @@ import { useTabFeatureFlags } from './hooks/useTabFeatureFlags';
|
|||||||
import { tradingRuntime, tradingTelemetry } from './lib/runtime';
|
import { tradingRuntime, tradingTelemetry } from './lib/runtime';
|
||||||
import { createTradeProfile, fetchTradeProfiles, updateTradeProfile } from './lib/profileApi';
|
import { createTradeProfile, fetchTradeProfiles, updateTradeProfile } from './lib/profileApi';
|
||||||
|
|
||||||
|
const ChatControl = lazy(() => import('./components/ChatControl').then((mod) => ({ default: mod.ChatControl })));
|
||||||
|
|
||||||
// ─── Helpers (preserved from original App.tsx) ───────────────────────────────
|
// ─── Helpers (preserved from original App.tsx) ───────────────────────────────
|
||||||
|
|
||||||
export const resolveProfileNameForAction = (
|
export const resolveProfileNameForAction = (
|
||||||
@ -262,7 +263,9 @@ function App() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Floating AI strategy assistant */}
|
{/* Floating AI strategy assistant */}
|
||||||
|
<Suspense fallback={null}>
|
||||||
<ChatControl profiles={chatProfiles} onApplyProfile={handleChatApply} />
|
<ChatControl profiles={chatProfiles} onApplyProfile={handleChatApply} />
|
||||||
|
</Suspense>
|
||||||
</AppContext.Provider>
|
</AppContext.Provider>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,17 +1,41 @@
|
|||||||
|
import { Suspense, lazy } from 'react';
|
||||||
import { Link, Routes, Route, useLocation } from 'react-router-dom';
|
import { Link, Routes, Route, useLocation } from 'react-router-dom';
|
||||||
import { Sidebar } from './Sidebar';
|
import { Sidebar } from './Sidebar';
|
||||||
import { Header } from './Header';
|
import { Header } from './Header';
|
||||||
import { RightPanel } from './RightPanel';
|
import { RightPanel } from './RightPanel';
|
||||||
import { Button } from '../ui/button';
|
import { Button } from '../ui/button';
|
||||||
import { HomeView } from '../../views/HomeView';
|
|
||||||
import { PortfolioView } from '../../views/PortfolioView';
|
const HomeView = lazy(() => import('../../views/HomeView').then((mod) => ({ default: mod.HomeView })));
|
||||||
import { ResearchView } from '../../views/ResearchView';
|
const PortfolioView = lazy(() => import('../../views/PortfolioView').then((mod) => ({ default: mod.PortfolioView })));
|
||||||
import { SimpleView } from '../../views/SimpleView';
|
const ResearchView = lazy(() => import('../../views/ResearchView').then((mod) => ({ default: mod.ResearchView })));
|
||||||
import { MarketsView } from '../../views/MarketsView';
|
const SimpleView = lazy(() => import('../../views/SimpleView').then((mod) => ({ default: mod.SimpleView })));
|
||||||
import { ScreenerView } from '../../views/ScreenerView';
|
const MarketsView = lazy(() => import('../../views/MarketsView').then((mod) => ({ default: mod.MarketsView })));
|
||||||
import { WatchlistView } from '../../views/WatchlistView';
|
const ScreenerView = lazy(() => import('../../views/ScreenerView').then((mod) => ({ default: mod.ScreenerView })));
|
||||||
import { AlertsView } from '../../views/AlertsView';
|
const WatchlistView = lazy(() => import('../../views/WatchlistView').then((mod) => ({ default: mod.WatchlistView })));
|
||||||
import { SettingsView } from '../../views/SettingsView';
|
const AlertsView = lazy(() => import('../../views/AlertsView').then((mod) => ({ default: mod.AlertsView })));
|
||||||
|
const SettingsView = lazy(() => import('../../views/SettingsView').then((mod) => ({ default: mod.SettingsView })));
|
||||||
|
|
||||||
|
function RouteFallback() {
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
aria-live="polite"
|
||||||
|
style={{
|
||||||
|
minHeight: 320,
|
||||||
|
borderRadius: 24,
|
||||||
|
border: '1px solid var(--border)',
|
||||||
|
background: 'var(--card)',
|
||||||
|
color: 'var(--foreground)',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: 700,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Loading workspace…
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function NotFoundView() {
|
function NotFoundView() {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
@ -64,6 +88,7 @@ export function AppShell() {
|
|||||||
<div className="dashboard-content-row">
|
<div className="dashboard-content-row">
|
||||||
{/* Scrollable main content */}
|
{/* Scrollable main content */}
|
||||||
<main className="dashboard-content">
|
<main className="dashboard-content">
|
||||||
|
<Suspense fallback={<RouteFallback />}>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<HomeView />} />
|
<Route path="/" element={<HomeView />} />
|
||||||
<Route path="/portfolio" element={<PortfolioView />} />
|
<Route path="/portfolio" element={<PortfolioView />} />
|
||||||
@ -76,6 +101,7 @@ export function AppShell() {
|
|||||||
<Route path="/settings" element={<SettingsView />} />
|
<Route path="/settings" element={<SettingsView />} />
|
||||||
<Route path="*" element={<NotFoundView />} />
|
<Route path="*" element={<NotFoundView />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
|
</Suspense>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
{/* Fixed right panel */}
|
{/* Fixed right panel */}
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import { useState } from 'react';
|
import { Suspense, lazy, useState } from 'react';
|
||||||
import { useAppContext } from '../context/AppContext';
|
import { useAppContext } from '../context/AppContext';
|
||||||
import { MarketplaceTab } from '../tabs/MarketplaceTab';
|
|
||||||
import { TopVolatile, AISetups } from '../components/MarketOpportunities';
|
import { TopVolatile, AISetups } from '../components/MarketOpportunities';
|
||||||
import type { StrategyPreset } from '../lib/PresetRegistry';
|
import type { StrategyPreset } from '../lib/PresetRegistry';
|
||||||
import { PageHeader } from '../components/ui/page-header';
|
import { PageHeader } from '../components/ui/page-header';
|
||||||
|
|
||||||
|
const MarketplaceTab = lazy(() => import('../tabs/MarketplaceTab').then((mod) => ({ default: mod.MarketplaceTab })));
|
||||||
|
|
||||||
export function MarketsView() {
|
export function MarketsView() {
|
||||||
const { botState, showMarketplaceTab } = useAppContext();
|
const { botState, showMarketplaceTab } = useAppContext();
|
||||||
const [, setClonedPreset] = useState<StrategyPreset | null>(null);
|
const [, setClonedPreset] = useState<StrategyPreset | null>(null);
|
||||||
@ -22,7 +23,9 @@ export function MarketsView() {
|
|||||||
<AISetups botState={botState} />
|
<AISetups botState={botState} />
|
||||||
</div>
|
</div>
|
||||||
{showMarketplaceTab && (
|
{showMarketplaceTab && (
|
||||||
|
<Suspense fallback={null}>
|
||||||
<MarketplaceTab onClone={handleClone} botState={botState} />
|
<MarketplaceTab onClone={handleClone} botState={botState} />
|
||||||
|
</Suspense>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user