Skip to main content
Back to Case Studies
Performance

How I optimized my bundle size by fixing tree-shaking in React

PerformanceCore Web VitalsReact

How I optimized my bundle size by fixing tree-shaking in React

The start of a journey toward LCP optimization across 8 Micro-Frontends.

The Starting Point: Why LCP matters

Largest Contentful Paint (LCP) measures the time it takes for the largest content element to appear. While auditing 8 Micro-Frontends (MFEs), I found an LCP of 12.7 seconds. My first step was clear: reduce the bundle weight.

My Toolkit

  • New Relic: Real-time observability. Critical for tracking real-world impact.
  • Webpack Bundle Analyzer: Creates a visual map of the bundle. This is where I spotted the "bloat."
  • Import Cost: VSCode extension showing the weight of each library directly in the editor.

The Barrel Files Issue

index.ts files that export everything from a folder are handy but dangerous. They often break Tree-shaking (the removal of dead code).

❌ Before (Barrel File):

// Even if I only use the Button, the bundler might pull in 
// the Modal, Chart, and Form as well.
import { Button } from '@/components'; 

✅ After (Granular Import):

// This ensures only the Button's code is included in the bundle.
import { Button } from '@/components/Button/Button';

Dynamic Icons: The silent villain

I was using a component that loaded icons based on a string prop. Since the bundler doesn't know which icon will be used at runtime, it bundled the entire library.

❌ Before (150KB extra):

const MyIcon = ({ name }) => <Icon name={name} />;

✅ After (5KB):

import { HomeIcon } from '@/icons/HomeIcon';
const MyIcon = () => <HomeIcon />;

First Milestone: -500KB in Bundle Size

By making these fixes, I cut the bundle from 850KB to 350KB. LCP dropped to 9.75s. It's not the 2.5s ideal yet, but now I have a lean foundation to tackle the next phase: rendering optimization.

“The fastest code is the code that is never sent to the user.”