Route-Based Splitting
Problem
Every route’s code loads upfront even though users only visit one page at a time. Navigating to the homepage downloads JavaScript for the profile page, settings panel, and every other route. Bundle sizes grow linearly with each new route added, making initial load times progressively worse.
Solution
Split code at route boundaries so each page loads only its required JavaScript. This is the most natural split point and provides significant bundle size wins.
Example
This example demonstrates route-based code splitting where each page is lazy-loaded, creating separate JavaScript bundles that download only when users navigate to that route.
// Each route loads its code on-demand
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
const Contact = lazy(() => import('./pages/Contact'));
<Routes>
{/* Home page code only loads when visiting / */}
<Route path="/" element={<Home />} />
{/* About page code only loads when visiting /about */}
<Route path="/about" element={<About />} />
{/* Contact page code only loads when visiting /contact */}
<Route path="/contact" element={<Contact />} />
</Routes>
Benefits
- Dramatically reduces initial bundle size by loading only current route’s code.
- Provides natural code split points that align with user navigation.
- Improves time-to-interactive by prioritizing current page over unused routes.
- Makes it easy to implement without complex analysis of code dependencies.
Tradeoffs
- Introduces loading states when navigating to new routes.
- Can make navigation feel slower if not combined with prefetching.
- Adds complexity with Suspense boundaries and error handling.
- May create too many small chunks if routes are too granular.