Performance Optimization Project — Bundle Analysis, Lazy Loading, Profiling, and Memory Leak Detection
A complete guide to improving React app performance through bundle analysis, lazy loading, performance profiling, and memory leak detection with practical steps and examples.
🚀 Performance Optimization Project
Speed up your React application using bundle analysis, lazy loading, and performance profiling.
🧠 Project Overview
Modern React apps often grow large and slow as features are added — larger bundles, unnecessary renders, and hidden memory leaks.
This project focuses on real techniques to detect and fix performance bottlenecks.
You will learn:
- Bundle Size Analysis
- Lazy Loading Implementation
- Performance Profiling
- Memory Leak Detection
We’ll apply these techniques step-by-step using simple examples and real-world patterns.
🧩 1. Bundle Size Analysis
🔹 Why It Matters
Every React app is bundled before deployment (using tools like Webpack or Vite).
If your bundle is too big, the app takes longer to download and start.
Reducing bundle size directly improves load time and Core Web Vitals.
💡 Real-World Example:
When Netflix reduced their JavaScript bundle size by 30%, the homepage load time improved by almost 40%.
🔸 Step 1: Build and Analyze
For Create React App:
npm run build
npx source-map-explorer "build/static/js/*.js"For Vite Projects:
npm run build
npx vite-bundle-visualizerThis shows a visual graph of your JavaScript files — which ones are large and where most space is used.
🔸 Step 2: Identify Heavy Modules
Common heavy libraries:
moment.js(usedayjs)lodash(import only what you need)react-icons(use subset imports)- Large image files or unused pages
🔸 Step 3: Optimize Imports
Instead of importing the whole library:
import _ from "lodash";Import only what you need:
import debounce from "lodash/debounce";🔸 Step 4: Dynamic Imports
Dynamic imports split code into smaller bundles:
const Chart = React.lazy(() => import("./Chart"));This loads the chart code only when the user opens that page.
💡 Real-World Example: YouTube loads heavy components like comments, analytics, and recommendations only when visible — speeding up initial load.
⚙️ 2. Lazy Loading Implementation
Lazy loading allows your app to load only what’s needed. It makes your initial load fast and delays secondary features until the user actually interacts with them.
🔹 Basic Lazy Loading
import React, { lazy, Suspense } from "react";
const Dashboard = lazy(() => import("./Dashboard"));
const Reports = lazy(() => import("./Reports"));
export default function App() {
return (
<Suspense fallback={<p>Loading...</p>}>
<Dashboard />
<Reports />
</Suspense>
);
}💡 How it Works:
- The browser loads only the required JavaScript bundle for the first screen.
- When the user visits
/reports, React dynamically loads that component.
🔹 Lazy Loading with Routes (React Router v6)
import { lazy } from "react";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
const Home = lazy(() => import("./pages/Home"));
const About = lazy(() => import("./pages/About"));
const router = createBrowserRouter([
{ path: "/", element: <Home /> },
{ path: "/about", element: <About /> },
]);
export default function App() {
return (
<React.Suspense fallback={<p>Loading...</p>}>
<RouterProvider router={router} />
</React.Suspense>
);
}💡 Real-World Example: Amazon loads heavy pages like “Product Details” or “Order History” only when users click those links, not at startup.
🔹 Lazy Loading Images (Frontend Trick)
<img loading="lazy" src="product-image.jpg" alt="Product" />Browsers natively delay loading off-screen images — improving startup speed.
💡 Real-World Example: Pinterest uses lazy loading for its endless grid of images, loading more only when you scroll down.
📊 3. Performance Profiling
Profiling means measuring which components take the most rendering time. React has built-in tools for this using the React Developer Tools browser extension.
🔹 Step 1: Open Profiler
In Chrome DevTools → Components tab → click Profiler. Start recording, then perform actions in your app (click, navigate, type). React will show:
- Render time of each component
- How often they render
- Which ones re-render unnecessarily
🔹 Step 2: Optimize Components
Let’s say you find that a List component re-renders on every keypress.
Before:
function List({ items, onClick }) {
return items.map((item) => <li onClick={() => onClick(item)}>{item}</li>);
}Problem: onClick is recreated on every render.
After optimization:
const List = React.memo(({ items, onClick }) => {
return items.map((item) => <li onClick={() => onClick(item)}>{item}</li>);
});💡 Real-World Example: Slack’s web app optimized its chat list re-renders — cutting down typing delay by 40%.
🔹 Step 3: Measure Time in Code (Manual Profiling)
console.time("fetchData");
await fetch("/api/tasks");
console.timeEnd("fetchData");💡 Use this technique in development to measure exact execution time for data fetching or heavy loops.
🧩 4. Memory Leak Detection
Memory leaks happen when your app keeps using memory that’s no longer needed — leading to slower performance over time.
🔹 Common Causes
- Unsubscribed event listeners
- Timers not cleared
- Unmounted components still using state
- Repeated API calls or intervals
🔹 Example of a Memory Leak
import { useEffect, useState } from "react";
export default function Timer() {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => setCount((c) => c + 1), 1000);
}, []); // ❌ no cleanup
return <h3>Count: {count}</h3>;
}This timer keeps running even after the component unmounts.
🔹 Fixing It
useEffect(() => {
const id = setInterval(() => setCount((c) => c + 1), 1000);
return () => clearInterval(id); // ✅ cleanup
}, []);💡 Real-World Example: In Spotify Web Player, uncleaned listeners caused slow playback switching. After fixing cleanup functions, memory usage dropped significantly.
🔹 Detecting Leaks in Chrome DevTools
- Open Chrome → Performance Tab → Record
- Perform user actions (like navigation or updates).
- Stop recording → open Memory Tab.
- If memory usage keeps rising even when you stop interacting — there’s a leak.
🔹 Best Practices
| Issue | Fix |
|---|---|
| Missing cleanup in useEffect | Always return cleanup functions |
| Listeners not removed | Remove event listeners in cleanup |
| Large arrays kept in state | Use pagination or windowing |
| Frequent API calls | Debounce or cancel previous requests |
🧾 Summary
| Concept | Goal | Real-World Example |
|---|---|---|
| Bundle Size Analysis | Reduce app load time | Netflix reduced homepage bundle by 30% |
| Lazy Loading | Load components only when needed | YouTube loads comments lazily |
| Performance Profiling | Identify slow components | Slack optimized message rendering |
| Memory Leak Detection | Prevent long-term slowdown | Spotify fixed playback memory issues |
💡 Final Project Insight
Performance isn’t just about speed — it’s about efficiency and stability. With these tools, you can measure exactly what slows your app and fix it scientifically.
In your next project:
- Start with bundle analysis
- Add lazy loading
- Regularly run profiling sessions
- Check for memory leaks before deployment
Big tech companies like Netflix, Spotify, and Airbnb continuously follow this process — that’s why their apps feel fast, no matter the size.
Performance Debugging — React Profiler, Chrome Tools, and Lighthouse Audits
Learn how to debug performance issues in React apps using React DevTools Profiler, Chrome Performance tools, and Lighthouse audits — with real-world examples and clear steps.
Performance Testing — Load Testing, Cache Analysis, and Response Optimization
Learn how to test app performance using Locust, analyze cache hit rates, and optimize response times with simple examples and real-world cases.