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 { useWebSocket } from './hooks/useWebSocket';
|
||||
import { useAuth } from './components/AuthContext';
|
||||
import { Login } from './components/Login';
|
||||
import { ResetPassword } from './components/ResetPassword';
|
||||
import { ChatControl } from './components/ChatControl';
|
||||
import { AppContext } from './context/AppContext';
|
||||
import { AppShell } from './components/layout/AppShell';
|
||||
import { useBacktestFeatureGate } from './backtest/useBacktestFeatureGate';
|
||||
@ -12,6 +11,8 @@ import { useTabFeatureFlags } from './hooks/useTabFeatureFlags';
|
||||
import { tradingRuntime, tradingTelemetry } from './lib/runtime';
|
||||
import { createTradeProfile, fetchTradeProfiles, updateTradeProfile } from './lib/profileApi';
|
||||
|
||||
const ChatControl = lazy(() => import('./components/ChatControl').then((mod) => ({ default: mod.ChatControl })));
|
||||
|
||||
// ─── Helpers (preserved from original App.tsx) ───────────────────────────────
|
||||
|
||||
export const resolveProfileNameForAction = (
|
||||
@ -262,7 +263,9 @@ function App() {
|
||||
)}
|
||||
|
||||
{/* Floating AI strategy assistant */}
|
||||
<ChatControl profiles={chatProfiles} onApplyProfile={handleChatApply} />
|
||||
<Suspense fallback={null}>
|
||||
<ChatControl profiles={chatProfiles} onApplyProfile={handleChatApply} />
|
||||
</Suspense>
|
||||
</AppContext.Provider>
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
||||
@ -1,17 +1,41 @@
|
||||
import { Suspense, lazy } from 'react';
|
||||
import { Link, Routes, Route, useLocation } from 'react-router-dom';
|
||||
import { Sidebar } from './Sidebar';
|
||||
import { Header } from './Header';
|
||||
import { RightPanel } from './RightPanel';
|
||||
import { Button } from '../ui/button';
|
||||
import { HomeView } from '../../views/HomeView';
|
||||
import { PortfolioView } from '../../views/PortfolioView';
|
||||
import { ResearchView } from '../../views/ResearchView';
|
||||
import { SimpleView } from '../../views/SimpleView';
|
||||
import { MarketsView } from '../../views/MarketsView';
|
||||
import { ScreenerView } from '../../views/ScreenerView';
|
||||
import { WatchlistView } from '../../views/WatchlistView';
|
||||
import { AlertsView } from '../../views/AlertsView';
|
||||
import { SettingsView } from '../../views/SettingsView';
|
||||
|
||||
const HomeView = lazy(() => import('../../views/HomeView').then((mod) => ({ default: mod.HomeView })));
|
||||
const PortfolioView = lazy(() => import('../../views/PortfolioView').then((mod) => ({ default: mod.PortfolioView })));
|
||||
const ResearchView = lazy(() => import('../../views/ResearchView').then((mod) => ({ default: mod.ResearchView })));
|
||||
const SimpleView = lazy(() => import('../../views/SimpleView').then((mod) => ({ default: mod.SimpleView })));
|
||||
const MarketsView = lazy(() => import('../../views/MarketsView').then((mod) => ({ default: mod.MarketsView })));
|
||||
const ScreenerView = lazy(() => import('../../views/ScreenerView').then((mod) => ({ default: mod.ScreenerView })));
|
||||
const WatchlistView = lazy(() => import('../../views/WatchlistView').then((mod) => ({ default: mod.WatchlistView })));
|
||||
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() {
|
||||
const location = useLocation();
|
||||
@ -64,18 +88,20 @@ export function AppShell() {
|
||||
<div className="dashboard-content-row">
|
||||
{/* Scrollable main content */}
|
||||
<main className="dashboard-content">
|
||||
<Routes>
|
||||
<Route path="/" element={<HomeView />} />
|
||||
<Route path="/portfolio" element={<PortfolioView />} />
|
||||
<Route path="/research" element={<ResearchView />} />
|
||||
<Route path="/simple" element={<SimpleView />} />
|
||||
<Route path="/markets" element={<MarketsView />} />
|
||||
<Route path="/screener" element={<ScreenerView />} />
|
||||
<Route path="/watchlist" element={<WatchlistView />} />
|
||||
<Route path="/alerts" element={<AlertsView />} />
|
||||
<Route path="/settings" element={<SettingsView />} />
|
||||
<Route path="*" element={<NotFoundView />} />
|
||||
</Routes>
|
||||
<Suspense fallback={<RouteFallback />}>
|
||||
<Routes>
|
||||
<Route path="/" element={<HomeView />} />
|
||||
<Route path="/portfolio" element={<PortfolioView />} />
|
||||
<Route path="/research" element={<ResearchView />} />
|
||||
<Route path="/simple" element={<SimpleView />} />
|
||||
<Route path="/markets" element={<MarketsView />} />
|
||||
<Route path="/screener" element={<ScreenerView />} />
|
||||
<Route path="/watchlist" element={<WatchlistView />} />
|
||||
<Route path="/alerts" element={<AlertsView />} />
|
||||
<Route path="/settings" element={<SettingsView />} />
|
||||
<Route path="*" element={<NotFoundView />} />
|
||||
</Routes>
|
||||
</Suspense>
|
||||
</main>
|
||||
|
||||
{/* Fixed right panel */}
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import { useState } from 'react';
|
||||
import { Suspense, lazy, useState } from 'react';
|
||||
import { useAppContext } from '../context/AppContext';
|
||||
import { MarketplaceTab } from '../tabs/MarketplaceTab';
|
||||
import { TopVolatile, AISetups } from '../components/MarketOpportunities';
|
||||
import type { StrategyPreset } from '../lib/PresetRegistry';
|
||||
import { PageHeader } from '../components/ui/page-header';
|
||||
|
||||
const MarketplaceTab = lazy(() => import('../tabs/MarketplaceTab').then((mod) => ({ default: mod.MarketplaceTab })));
|
||||
|
||||
export function MarketsView() {
|
||||
const { botState, showMarketplaceTab } = useAppContext();
|
||||
const [, setClonedPreset] = useState<StrategyPreset | null>(null);
|
||||
@ -22,7 +23,9 @@ export function MarketsView() {
|
||||
<AISetups botState={botState} />
|
||||
</div>
|
||||
{showMarketplaceTab && (
|
||||
<MarketplaceTab onClone={handleClone} botState={botState} />
|
||||
<Suspense fallback={null}>
|
||||
<MarketplaceTab onClone={handleClone} botState={botState} />
|
||||
</Suspense>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user