Route-Based Code Splitting for Faster SPAs
A typical React project with 50 pages and no optimization has a 2.5 MB initial bundle, causing LCP over 5 seconds on 3G. The user waits for the checkout page to load when they only opened the catalog. We fix this by splitting code by routes: each route loads as a separate chunk. Instead of a monolithic JS file, the browser gets only what is needed now. The result — LCP drops by 40–60%, and TTFB improves due to smaller data volume. Additionally, browser memory consumption decreases and the number of initial network requests drops. In our experience, a typical project shrinks the initial bundle from 2.5 MB to 500 KB gzipped.
What Problem Does Route-Based Code Splitting Solve?
Without splitting, the entire app code — catalog, cart, admin — is downloaded on entry. This slows first load, increases data usage, and hurts Core Web Vitals. Route-based code splitting eliminates these issues: each navigation loads only the needed chunk, and hover-based prefetch makes navigation instant. Compared to simple minification, code splitting gives 2–3 times greater load time reduction because it reduces the code executed at startup. Also, CDN traffic savings are substantial for projects with high traffic.
| Component | Before Code Splitting | After |
|---|---|---|
| Home | 800 KB | 150 KB |
| Catalog | 900 KB | 200 KB |
| Cart | 600 KB | 120 KB |
How We Implement Code Splitting in React
React Router v6 + React.lazy
We use React.lazy for each route and Suspense for the loading state:
// router/index.tsx const Home = lazy(() => import('@/pages/Home')) const Catalog = lazy(() => import('@/pages/Catalog')) const Checkout = lazy(() => import('@/pages/Checkout')) const router = createBrowserRouter([ { path: '/', element: <AppLayout />, children: [ { index: true, element: <Home /> }, { path: 'catalog', element: <Catalog /> }, { path: 'checkout', element: <Checkout /> }, ], }, ]) function App() { return ( <Suspense fallback={<PageLoader />}> <RouterProvider router={router} /> </Suspense> ) } Vite creates a separate chunk for each dynamic import. For chunk naming, we use manualChunks in the config:
Example manualChunks configuration
// vite.config.ts manualChunks: { 'vendor-react': ['react', 'react-dom', 'react-router-dom'], 'vendor-ui': ['@radix-ui/react-dialog', '@radix-ui/react-dropdown-menu'], } Next.js App Router
In Next.js, code splitting works out of the box: each page.tsx is a separate segment. For heavy components inside pages, we use dynamic():
const FilterPanel = dynamic(() => import('@/components/FilterPanel'), { loading: () => <FilterSkeleton />, }) const StoreMap = dynamic(() => import('@/components/StoreMap'), { ssr: false, loading: () => <div className="h-96 bg-muted animate-pulse" />, }) Prefetching and Error Boundary
We prefetch a chunk on hover by calling import('./Page') inside onMouseEnter. In Next.js, <Link> automatically prefetches chunks for visible links. For loading errors (no network, 404), we add a ChunkErrorBoundary that shows a "Retry" button and reloads the page. As the React documentation states, Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI. This ensures the user never sees a blank screen when a chunk load fails.
What Our Work Includes
- Bundle analysis using source-map-explorer and report.
- Route-based code splitting: dynamic import for each route.
- Vendor chunk optimization: extracting common libraries, tree-shaking.
- Prefetch and error boundary setup.
- Load testing on 3G and 4G, Core Web Vitals measurement.
- Documentation on chunk structure and recommendations for further optimization.
Completing all steps typically takes 1 to 3 days depending on project complexity. Pricing is customized after scope estimation.
Why Choose Us for Code Splitting?
We have 5+ years of experience optimizing React and Next.js applications. We guarantee the initial bundle will not exceed 200 KB gzipped, and each route chunk will be under 100 KB. We set up size analytics so you can track regressions. Contact us — we'll evaluate your project within one day.
| Target Metric | Value |
|---|---|
| Initial bundle | <200 KB gzipped |
| Each route chunk | <100 KB gzipped |
| LCP improvement | 40-60% |
| Setup duration | from 1 day |
Timeline and Pricing
For an existing router — 1 day. Full cycle with analysis, vendor splitting, and prefetch — 2–3 days. Pricing is customized based on application complexity. Reach out — we'll provide a fixed quote.
Optimize your project: order route-based code splitting to speed up loading and improve user experience. If you still have questions, get a free consultation — we'll explain in detail how to boost your SPA performance.







