Performance Testing with Lighthouse and Web Vitals

Loading

Performance testing is crucial for ensuring your React application delivers an optimal user experience. Here’s a comprehensive guide to using Lighthouse and Web Vitals for measuring and improving your React app’s performance.

Core Web Vitals Implementation

1. Measuring Web Vitals in React

// web-vitals.js
import { getCLS, getFID, getLCP, getFCP, getTTFB } from 'web-vitals';

function sendToAnalytics({ name, delta, value, id }) {
  // Send to your analytics platform
  console.log(name, value);

  // Example: Send to Google Analytics
  if (typeof window.gtag === 'function') {
    window.gtag('event', name, {
      event_category: 'Web Vitals',
      value: delta,
      non_interaction: true,
    });
  }
}

// Initialize Web Vitals tracking
export function trackWebVitals() {
  getCLS(sendToAnalytics);
  getFID(sendToAnalytics);
  getLCP(sendToAnalytics);
  getFCP(sendToAnalytics);
  getTTFB(sendToAnalytics);
}

2. Integrating with React

// index.js
import { trackWebVitals } from './web-vitals';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want to measure performance, pass a function
if (process.env.NODE_ENV === 'production') {
  trackWebVitals();
}

Lighthouse Testing

3. Automated Lighthouse CI

# .github/workflows/lighthouse.yml
name: Lighthouse CI

on: [push]

jobs:
  lighthouse:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - run: npm install
      - run: npm run build
      - uses: actions/upload-artifact@v3
        with:
          name: build
          path: build
      - name: Run Lighthouse
        uses: treosh/lighthouse-ci-action@v9
        with:
          urls: |
            http://localhost:3000
            http://localhost:3000/dashboard
          uploadArtifacts: true
          temporaryPublicStorage: true
          configPath: .lighthouserc.json

4. Lighthouse Configuration

// .lighthouserc.json
{
  "ci": {
    "collect": {
      "numberOfRuns": 3,
      "settings": {
        "configPath": "./lighthouse-config.js",
        "chromeFlags": "--no-sandbox --headless",
        "onlyCategories": ["performance", "accessibility", "best-practices", "seo"]
      }
    },
    "assert": {
      "preset": "lighthouse:no-pwa",
      "assertions": {
        "first-contentful-paint": ["warn", {"maxNumericValue": 2000}],
        "largest-contentful-paint": ["error", {"maxNumericValue": 2500}],
        "cumulative-layout-shift": ["error", {"maxNumericValue": 0.1}],
        "interactive": ["error", {"maxNumericValue": 3500}],
        "speed-index": ["error", {"maxNumericValue": 4300}]
      }
    }
  }
}

Performance Optimization Techniques

5. Code Splitting in React

// Lazy load components
const Dashboard = React.lazy(() => import('./Dashboard'));
const Settings = React.lazy(() => import('./Settings'));

function App() {
  return (
    <Suspense fallback={<LoadingSpinner />}>
      <Routes>
        <Route path="/dashboard" element={<Dashboard />} />
        <Route path="/settings" element={<Settings />} />
      </Routes>
    </Suspense>
  );
}

6. Image Optimization

// ResponsiveImage component
import { useState, useEffect } from 'react';

function ResponsiveImage({ src, alt, width, height }) {
  const [loaded, setLoaded] = useState(false);

  return (
    <div style={{ position: 'relative', paddingBottom: `${(height/width)*100}%` }}>
      <img
        src={src}
        alt={alt}
        loading="lazy"
        style={{
          position: 'absolute',
          top: 0,
          left: 0,
          width: '100%',
          height: '100%',
          opacity: loaded ? 1 : 0,
          transition: 'opacity 0.3s',
          objectFit: 'cover'
        }}
        onLoad={() => setLoaded(true)}
      />
      {!loaded && <Placeholder />}
    </div>
  );
}

Advanced Performance Monitoring

7. Custom Performance Metrics

// track.js
export function trackPerfMetric(name, startTime) {
  const duration = performance.now() - startTime;

  // Send to analytics
  if (window.analytics) {
    window.analytics.track(name, { duration });
  }

  // Log to console in development
  if (process.env.NODE_ENV === 'development') {
    console.log(`${name}: ${duration.toFixed(2)}ms`);
  }
}

// Usage in components
function ProductList() {
  useEffect(() => {
    const start = performance.now();

    return () => {
      trackPerfMetric('ProductList render', start);
    };
  }, []);

  return <div>...</div>;
}

8. Resource Timing API

// resource-timing.js
function analyzeResources() {
  const resources = performance.getEntriesByType('resource');
  const jsResources = resources.filter(r => r.initiatorType === 'script');

  const report = {
    totalResources: resources.length,
    totalJS: jsResources.length,
    jsSize: jsResources.reduce((sum, r) => sum + r.transferSize, 0),
    slowResources: resources.filter(r => r.duration > 500)
  };

  return report;
}

// Send report every 5 minutes
setInterval(() => {
  const report = analyzeResources();
  navigator.sendBeacon('/perf-metrics', JSON.stringify(report));
}, 300000);

Performance Budgets

9. Performance Budget Configuration

// package.json
{
  "performance-budget": {
    "resources": [
      {
        "resourceType": "document",
        "budget": 50
      },
      {
        "resourceType": "script",
        "budget": 200
      },
      {
        "resourceType": "stylesheet",
        "budget": 50
      },
      {
        "resourceType": "image",
        "budget": 300
      },
      {
        "resourceType": "total",
        "budget": 1000
      }
    ],
    "timings": [
      {
        "metric": "first-contentful-paint",
        "budget": 2000
      },
      {
        "metric": "largest-contentful-paint",
        "budget": 2500
      },
      {
        "metric": "cumulative-layout-shift",
        "budget": 0.1
      }
    ]
  }
}

10. Enforcing Budgets in CI

# .github/workflows/performance-budget.yml
name: Performance Budget

on: [pull_request]

jobs:
  performance:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - run: npm install
      - run: npm run build
      - name: Run Performance Budget Checker
        uses: foo-software/lighthouse-check-action@master
        with:
          urls: http://localhost:3000
          budgetPath: ./performance-budget.json
          githubAccessToken: ${{ secrets.GITHUB_TOKEN }}

Visualization and Reporting

11. Lighthouse CI Server

# Install Lighthouse CI server
npm install -g @lhci/cli

# Run server
lhci server --storage.storageMethod=sqlite --storage.sqliteDatabasePath=./lhci.db

# Upload reports
lhci upload --serverBaseUrl=http://localhost:9001 --token=your-token

12. Grafana Dashboard for Web Vitals

{
  "panels": [
    {
      "title": "Core Web Vitals",
      "type": "graph",
      "datasource": "Prometheus",
      "targets": [
        {
          "expr": "avg(web_vitals_lcp)",
          "legendFormat": "LCP"
        },
        {
          "expr": "avg(web_vitals_fid)",
          "legendFormat": "FID"
        },
        {
          "expr": "avg(web_vitals_cls)",
          "legendFormat": "CLS"
        }
      ],
      "thresholds": [
        {
          "value": 2500,
          "color": "red",
          "op": "gt",
          "line": true
        }
      ]
    }
  ]
}

Best Practices Checklist

  1. Measure Continuously
  • [ ] Set up Lighthouse CI
  • [ ] Track Web Vitals in production
  • [ ] Monitor performance budgets
  1. Optimize Loading
  • [ ] Implement code splitting
  • [ ] Optimize images
  • [ ] Preload critical resources
  1. Improve Rendering
  • [ ] Reduce unnecessary re-renders
  • [ ] Virtualize long lists
  • [ ] Use efficient CSS
  1. Monitor Third Parties
  • [ ] Audit third-party scripts
  • [ ] Lazy load non-critical scripts
  • [ ] Set up resource timing monitoring
  1. Set Performance Goals
  • [ ] Define performance budgets
  • [ ] Establish Core Web Vitals targets
  • [ ] Create team performance KPIs
  1. Visualize Data
  • [ ] Set up dashboards
  • [ ] Create performance reports
  • [ ] Share metrics with stakeholders
  1. Automate Alerts
  • [ ] Configure performance regressions alerts
  • [ ] Set up budget violation notifications
  • [ ] Create CI blocking rules

Leave a Reply

Your email address will not be published. Required fields are marked *