4.2 KiB
Lazy Loading Implementation
Overview
The application now implements lazy loading (code splitting) for all view components to significantly improve initial load time. Each view is loaded on-demand only when the user navigates to it.
How It Works
React.lazy()
All view components are wrapped with React.lazy() which enables dynamic imports:
const DashboardView = lazy(() => import('@/components/views').then(m => ({ default: m.DashboardView })))
Suspense Boundary
The ViewRouter component wraps all lazy-loaded views in a Suspense boundary with a loading fallback:
<Suspense fallback={<LoadingFallback />}>
{renderView()}
</Suspense>
Smart Preloading
The application implements intelligent preloading strategies to make navigation feel instant:
- Idle Preloading: After 2 seconds of initial load, the most commonly used views are preloaded in the background
- Hover Preloading: When hovering over navigation items, the corresponding view starts loading immediately
- Deduplication: Views are only preloaded once and tracked to avoid redundant downloads
Preloading Strategy
Automatic Preloading
Common views are automatically preloaded after initial page load:
- Timesheets
- Billing
- Reports
- Missing Timesheets Report
Hover-Based Preloading
All navigation items trigger view preloading on hover, making navigation feel instant for users who hover before clicking.
Benefits
- Faster Initial Load: Only the dashboard view loads initially, not all 26+ views
- Reduced Bundle Size: Main bundle is smaller, improving Time to Interactive (TTI)
- Progressive Loading: Views load as needed, spreading the load over time
- Better Performance: Reduces memory usage and parsing time on initial load
- Automatic Code Splitting: Vite automatically creates separate chunks for each lazy-loaded component
- Instant Navigation: Preloading ensures commonly used views are ready immediately
- Smooth UX: Loading states provide feedback when views aren't yet loaded
Lazy-Loaded Views
All views are now lazy-loaded:
Core Views
- Dashboard
- Timesheets
- Billing
- Payroll
- Compliance
- Expenses
- Reports
Feature Views
- Currency Management
- Email Template Manager
- Invoice Template Manager
- QR Timesheet Scanner
- Missing Timesheets Report
- Purchase Order Manager
- Onboarding Workflow Manager
- Audit Trail Viewer
- Notification Rules Manager
- Batch Import Manager
- Rate Template Manager
- Custom Report Builder
- Holiday Pay Manager
- Contract Validator
- Shift Pattern Manager
- Query Language Guide
- Roadmap View
- Component Showcase
- Business Logic Demo
Loading States
When navigating to a new view:
- User clicks navigation item
- Loading spinner appears (centered, large size)
- View chunk downloads (if not cached)
- View renders and replaces loading spinner
The loading fallback uses a minimum height of 400px to prevent layout shift.
Performance Metrics
Before Lazy Loading
- Initial bundle includes all 26+ views
- Larger initial download size
- Longer Time to Interactive
After Lazy Loading
- Initial bundle includes only essential code + dashboard
- Views load in separate chunks (typically 5-50KB each)
- Faster initial page load
- Views cached after first load
- Hover preloading makes navigation feel instant
Browser Caching
Once a view chunk is loaded, it's cached by the browser and won't need to be re-downloaded on subsequent navigations.
Implementation Files
/src/components/ViewRouter.tsx- Lazy loading and suspense boundary/src/lib/view-preloader.ts- Preloading logic and view map/src/hooks/use-view-preload.ts- Idle preloading hook/src/components/nav/NavItem.tsx- Hover-based preloading integration
Future Improvements
Potential optimizations:
- Usage Analytics: Track which views are most commonly accessed and adjust preloading strategy
- Network-Aware Loading: Adjust preloading behavior based on connection speed
- Progressive Hydration: Load critical views first, defer others
- Bundle size monitoring: Track chunk sizes to keep them optimized
- Predictive Preloading: Learn user navigation patterns and preload accordingly