My App
React

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:

  1. Bundle Size Analysis
  2. Lazy Loading Implementation
  3. Performance Profiling
  4. 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-visualizer

This 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 (use dayjs)
  • 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

  1. Unsubscribed event listeners
  2. Timers not cleared
  3. Unmounted components still using state
  4. 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

  1. Open Chrome → Performance Tab → Record
  2. Perform user actions (like navigation or updates).
  3. Stop recording → open Memory Tab.
  4. If memory usage keeps rising even when you stop interacting — there’s a leak.

🔹 Best Practices

IssueFix
Missing cleanup in useEffectAlways return cleanup functions
Listeners not removedRemove event listeners in cleanup
Large arrays kept in stateUse pagination or windowing
Frequent API callsDebounce or cancel previous requests

🧾 Summary

ConceptGoalReal-World Example
Bundle Size AnalysisReduce app load timeNetflix reduced homepage bundle by 30%
Lazy LoadingLoad components only when neededYouTube loads comments lazily
Performance ProfilingIdentify slow componentsSlack optimized message rendering
Memory Leak DetectionPrevent long-term slowdownSpotify 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.