How do you analyze and optimize React bundle size? What tools and techniques do you use?

3 minintermediatereactanalyzeoptimizebundle

Quick Answer

Bundle analysis is crucial for optimizing React application performance and loading times.

Detailed Answer

How do you analyze and optimize React bundle size? What tools and techniques do you use?

Bundle analysis is crucial for optimizing React application performance and loading times.

Bundle Analysis Tools:

  1. Webpack Bundle Analyzer:
# Install
npm install --save-dev webpack-bundle-analyzer

# Add to webpack.config.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin({
      analyzerMode: 'server',
      openAnalyzer: true,
    })
  ]
};

# Or use with Create React App
npm install --save-dev webpack-bundle-analyzer
npx webpack-bundle-analyzer build/static/js/*.js
  1. Source Map Explorer:
# Install
npm install --save-dev source-map-explorer

# Analyze build
npx source-map-explorer 'build/static/js/*.js'
  1. Bundlephobia:
# Check package sizes before installing
npx bundlephobia lodash
npx bundlephobia react-router-dom

Code Splitting Strategies:

// 1. Route-based splitting
import { lazy, Suspense } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';

const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
const Contact = lazy(() => import('./pages/Contact'));

function App() {
  return (
    <BrowserRouter>
      <Suspense fallback={<div>Loading...</div>}>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/about" element={<About />} />
          <Route path="/contact" element={<Contact />} />
        </Routes>
      </Suspense>
    </BrowserRouter>
  );
}

// 2. Component-based splitting
const HeavyChart = lazy(() => import('./components/HeavyChart'));
const DataTable = lazy(() => import('./components/DataTable'));

function Dashboard() {
  const [showChart, setShowChart] = useState(false);
  
  return (
    <div>
      <button onClick={() => setShowChart(true)}>Show Chart</button>
      {showChart && (
        <Suspense fallback={<div>Loading chart...</div>}>
          <HeavyChart />
        </Suspense>
      )}
    </div>
  );
}

// 3. Library splitting
const loadMoment = () => import('moment');
const loadChart = () => import('chart.js');

async function handleExport() {
  const moment = await loadMoment();
  const chart = await loadChart();
  // Use libraries
}

Bundle Optimization Techniques:

// 1. Tree shaking
// ✅ Good - only imports what you need
import { debounce } from 'lodash-es';
import { format } from 'date-fns';

// ❌ Bad - imports entire library
import _ from 'lodash';
import * as dateFns from 'date-fns';

// 2. Dynamic imports for large libraries
async function loadPDFLibrary() {
  const { PDFDocument } = await import('pdf-lib');
  return PDFDocument;
}

// 3. Vendor chunk splitting
// webpack.config.js
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all',
        },
        react: {
          test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
          name: 'react',
          chunks: 'all',
        }
      }
    }
  }
};

Performance Monitoring:

// 1. Bundle size monitoring
// package.json
{
  "scripts": {
    "analyze": "npm run build && npx webpack-bundle-analyzer build/static/js/*.js",
    "size-limit": "size-limit"
  }
}

// 2. Runtime performance monitoring
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';

function sendToAnalytics(metric) {
  // Send to your analytics service
  console.log(metric);
}

getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getFCP(sendToAnalytics);
getLCP(sendToAnalytics);
getTTFB(sendToAnalytics);

// 3. Bundle size tracking in CI
// .github/workflows/bundle-size.yml
name: Bundle Size
on: [pull_request]
jobs:
  bundle-size:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
      - run: npm ci
      - run: npm run build
      - uses: preactjs/compressed-size-action@v2
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          pattern: './build/static/js/*.js'