How We Cut Our React App's Bundle Size in Half

February 20, 2025 (2w ago)

How We Cut Our React App's Bundle Size in Half

Our React application's bundle size had reached 1.54MB (gzipped). The app worked fine, but loading times kept increasing. This post explains the steps we took to reduce the bundle size in half and its impact on performance.

Understanding the Problem

Lighthouse and Chrome DevTools painted a clear picture:

The Optimization Strategy

1. Route-Based Code Splitting

In our app using createBrowserRouter from React Router 6, we implemented route-based code-splitting to defer code loading until a user navigates to the relevant route:

import React, { lazy, Suspense } from "react";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
 
const LazyLoadedPage = lazy(() => import("./LazyLoadedPage"));
 
const router = createBrowserRouter([
  {
    path: "/feature",
    element: (
      <Suspense fallback={<div>Loading...</div>}>
        <LazyLoadedPage />
      </Suspense>
    ),
  },
]);

2. Strategic Library Loading

Heavy dependencies don't need to load immediately. The key is to move imports inside the functions that use them:

// Before - importing at the top level
import { PDFDocument } from "@react-pdf/renderer";
import * as XLSX from "xlsx";
 
// After - inline imports when needed
async function generatePDF(data) {
  const { PDFDocument } = await import("@react-pdf/renderer");
  // PDF generation logic
}
 
async function exportToExcel(data) {
  const XLSX = await import("xlsx");
  // Excel export logic
}

We applied this pattern to several large dependencies:

Other common libraries worth deferring in React apps:

The pattern remains consistent: identify when users need the functionality, and load it at that moment. This approach is particularly helpful during initial page loads.

3. Measurement-Driven Optimization

Three tools drove our decisions:

The Results

Metric Improvement
Main Bundle Size -49.5%
First Contentful Paint +28.5%
Total Blocking Time +20%
Speed Index +46.4%

Key Learnings

  1. Target the right components for code splitting. Focus on larger features that deliver meaningful impact.

  2. Performance tools reveal opportunities you might miss otherwise. Regular bundle analysis became essential to our process.

  3. Performance optimization doesn't stop. Each improvement reveals new opportunities.

Maintaining Performance

Three practices keep our bundle size in check:

Conclusion

Performance optimization delivers real user value. We reduced our bundle size by carefully analyzing and making targeted improvements, improving every key performance indicator.

Three steps can start your optimization journey:

  1. Measure your current state
  2. Split code strategically
  3. Monitor consistently

Every kilobyte impacts user experience. Start measuring yours today.