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 />;