Lazy loading for smaller build chunks/faster initial load
This commit is contained in:
@@ -1,27 +1,41 @@
|
||||
import { Routes, Route, useNavigate, Navigate, useLocation } from 'react-router-dom';
|
||||
import { MainLayout } from './components/layout/MainLayout';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { Products } from './pages/Products';
|
||||
import { Overview } from './pages/Overview';
|
||||
import { Settings } from './pages/Settings';
|
||||
import { Analytics } from './pages/Analytics';
|
||||
import { Toaster } from '@/components/ui/sonner';
|
||||
import PurchaseOrders from './pages/PurchaseOrders';
|
||||
import { Login } from './pages/Login';
|
||||
import { useEffect } from 'react';
|
||||
import { useEffect, Suspense, lazy } from 'react';
|
||||
import config from './config';
|
||||
import { RequireAuth } from './components/auth/RequireAuth';
|
||||
import Forecasting from "@/pages/Forecasting";
|
||||
import { Vendors } from '@/pages/Vendors';
|
||||
import { Categories } from '@/pages/Categories';
|
||||
import { Import } from '@/pages/Import';
|
||||
import { AuthProvider } from './contexts/AuthContext';
|
||||
import { Protected } from './components/auth/Protected';
|
||||
import { FirstAccessiblePage } from './components/auth/FirstAccessiblePage';
|
||||
import { Brands } from '@/pages/Brands';
|
||||
import { Chat } from '@/pages/Chat';
|
||||
import { Dashboard } from '@/pages/Dashboard';
|
||||
import { SmallDashboard } from '@/pages/SmallDashboard';
|
||||
import { PageLoading } from '@/components/ui/page-loading';
|
||||
|
||||
// Always loaded components (Login and Settings stay in main bundle)
|
||||
import { Settings } from './pages/Settings';
|
||||
import { Login } from './pages/Login';
|
||||
|
||||
// Lazy load the 4 main chunks you wanted:
|
||||
|
||||
// 1. Core inventory app - loaded as one chunk when any inventory page is accessed
|
||||
const Overview = lazy(() => import('./pages/Overview'));
|
||||
const Products = lazy(() => import('./pages/Products').then(module => ({ default: module.Products })));
|
||||
const Analytics = lazy(() => import('./pages/Analytics').then(module => ({ default: module.Analytics })));
|
||||
const Forecasting = lazy(() => import('./pages/Forecasting'));
|
||||
const Vendors = lazy(() => import('./pages/Vendors'));
|
||||
const Categories = lazy(() => import('./pages/Categories'));
|
||||
const Brands = lazy(() => import('./pages/Brands'));
|
||||
const PurchaseOrders = lazy(() => import('./pages/PurchaseOrders'));
|
||||
|
||||
// 2. Dashboard app - separate chunk
|
||||
const Dashboard = lazy(() => import('./pages/Dashboard'));
|
||||
const SmallDashboard = lazy(() => import('./pages/SmallDashboard'));
|
||||
|
||||
// 3. Product import - separate chunk
|
||||
const Import = lazy(() => import('./pages/Import').then(module => ({ default: module.Import })));
|
||||
|
||||
// 4. Chat archive - separate chunk
|
||||
const Chat = lazy(() => import('./pages/Chat').then(module => ({ default: module.Chat })));
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
function App() {
|
||||
@@ -75,78 +89,117 @@ function App() {
|
||||
<AuthProvider>
|
||||
<Toaster richColors position="top-center" />
|
||||
<Routes>
|
||||
{/* Always loaded routes */}
|
||||
<Route path="/login" element={<Login />} />
|
||||
<Route path="/small" element={<SmallDashboard />} />
|
||||
<Route path="/small" element={
|
||||
<Suspense fallback={<PageLoading />}>
|
||||
<SmallDashboard />
|
||||
</Suspense>
|
||||
} />
|
||||
<Route element={
|
||||
<RequireAuth>
|
||||
<MainLayout />
|
||||
</RequireAuth>
|
||||
}>
|
||||
{/* Core inventory app routes - will be lazy loaded */}
|
||||
<Route index element={
|
||||
<Protected page="dashboard" fallback={<FirstAccessiblePage />}>
|
||||
<Suspense fallback={<PageLoading />}>
|
||||
<Overview />
|
||||
</Suspense>
|
||||
</Protected>
|
||||
} />
|
||||
<Route path="/" element={
|
||||
<Protected page="dashboard">
|
||||
<Suspense fallback={<PageLoading />}>
|
||||
<Overview />
|
||||
</Suspense>
|
||||
</Protected>
|
||||
} />
|
||||
<Route path="/products" element={
|
||||
<Protected page="products">
|
||||
<Suspense fallback={<PageLoading />}>
|
||||
<Products />
|
||||
</Protected>
|
||||
} />
|
||||
<Route path="/import" element={
|
||||
<Protected page="import">
|
||||
<Import />
|
||||
</Suspense>
|
||||
</Protected>
|
||||
} />
|
||||
<Route path="/categories" element={
|
||||
<Protected page="categories">
|
||||
<Suspense fallback={<PageLoading />}>
|
||||
<Categories />
|
||||
</Suspense>
|
||||
</Protected>
|
||||
} />
|
||||
<Route path="/vendors" element={
|
||||
<Protected page="vendors">
|
||||
<Suspense fallback={<PageLoading />}>
|
||||
<Vendors />
|
||||
</Suspense>
|
||||
</Protected>
|
||||
} />
|
||||
<Route path="/brands" element={
|
||||
<Protected page="brands">
|
||||
<Suspense fallback={<PageLoading />}>
|
||||
<Brands />
|
||||
</Suspense>
|
||||
</Protected>
|
||||
} />
|
||||
<Route path="/purchase-orders" element={
|
||||
<Protected page="purchase_orders">
|
||||
<Suspense fallback={<PageLoading />}>
|
||||
<PurchaseOrders />
|
||||
</Suspense>
|
||||
</Protected>
|
||||
} />
|
||||
<Route path="/analytics" element={
|
||||
<Protected page="analytics">
|
||||
<Suspense fallback={<PageLoading />}>
|
||||
<Analytics />
|
||||
</Suspense>
|
||||
</Protected>
|
||||
} />
|
||||
<Route path="/forecasting" element={
|
||||
<Protected page="forecasting">
|
||||
<Suspense fallback={<PageLoading />}>
|
||||
<Forecasting />
|
||||
</Suspense>
|
||||
</Protected>
|
||||
} />
|
||||
|
||||
{/* Always loaded settings */}
|
||||
<Route path="/settings" element={
|
||||
<Protected page="settings">
|
||||
<Settings />
|
||||
</Protected>
|
||||
} />
|
||||
<Route path="/forecasting" element={
|
||||
<Protected page="forecasting">
|
||||
<Forecasting />
|
||||
|
||||
{/* Product import - separate chunk */}
|
||||
<Route path="/import" element={
|
||||
<Protected page="import">
|
||||
<Suspense fallback={<PageLoading />}>
|
||||
<Import />
|
||||
</Suspense>
|
||||
</Protected>
|
||||
} />
|
||||
|
||||
{/* Chat archive - separate chunk */}
|
||||
<Route path="/chat" element={
|
||||
<Protected page="chat">
|
||||
<Suspense fallback={<PageLoading />}>
|
||||
<Chat />
|
||||
</Suspense>
|
||||
</Protected>
|
||||
} />
|
||||
|
||||
{/* Dashboard app - separate chunk */}
|
||||
<Route path="/dashboard" element={
|
||||
<Protected page="dashboard">
|
||||
<Suspense fallback={<PageLoading />}>
|
||||
<Dashboard />
|
||||
</Suspense>
|
||||
</Protected>
|
||||
} />
|
||||
|
||||
<Route path="*" element={<Navigate to="/" replace />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
|
||||
31
inventory/src/components/ui/page-loading.tsx
Normal file
31
inventory/src/components/ui/page-loading.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import { Loader2 } from 'lucide-react';
|
||||
|
||||
interface PageLoadingProps {
|
||||
message?: string;
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
}
|
||||
|
||||
export const PageLoading = ({ message = 'Loading...', size = 'md' }: PageLoadingProps) => {
|
||||
const sizeClasses = {
|
||||
sm: 'h-6 w-6',
|
||||
md: 'h-8 w-8',
|
||||
lg: 'h-12 w-12'
|
||||
};
|
||||
|
||||
const containerClasses = {
|
||||
sm: 'min-h-[200px]',
|
||||
md: 'min-h-[400px]',
|
||||
lg: 'min-h-[600px]'
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`flex items-center justify-center ${containerClasses[size]}`}>
|
||||
<div className="flex flex-col items-center space-y-4">
|
||||
<Loader2 className={`animate-spin text-primary ${sizeClasses[size]}`} />
|
||||
<p className="text-sm text-muted-foreground animate-pulse">{message}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PageLoading;
|
||||
File diff suppressed because one or more lines are too long
@@ -221,10 +221,14 @@ export default defineConfig(({ mode }) => {
|
||||
build: {
|
||||
outDir: "build",
|
||||
sourcemap: true,
|
||||
chunkSizeWarningLimit: 1000,
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks: {
|
||||
vendor: ["react", "react-dom", "react-router-dom"],
|
||||
// Simple static chunking approach - safer than function-based chunking
|
||||
'react-vendor': ['react', 'react-dom', 'react-router-dom'],
|
||||
'ui-vendor': ['@radix-ui/react-dialog', '@radix-ui/react-dropdown-menu', 'lucide-react'],
|
||||
'query-vendor': ['@tanstack/react-query'],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user