Skip to content

React Project Build and Deployment

Overview

This chapter will learn how to build and deploy React applications, including production optimization, build configuration, deployment strategies, and performance monitoring.

🔧 Project Building

Production Build

bash
# Create React App build command
npm run build

# Build output analysis
npm install -g serve
serve -s build

# Build analysis
npm install --save-dev webpack-bundle-analyzer
npm run build -- --analyze

Environment Variable Configuration

bash
# .env file
REACT_APP_API_URL=http://localhost:3001
REACT_APP_VERSION=1.0.0

# .env.production
REACT_APP_API_URL=https://api.production.com
REACT_APP_VERSION=1.0.0
jsx
// Environment variable usage
function EnvironmentConfig() {
  const config = {
    apiUrl: process.env.REACT_APP_API_URL,
    version: process.env.REACT_APP_VERSION,
    isDevelopment: process.env.NODE_ENV === 'development',
    isProduction: process.env.NODE_ENV === 'production'
  };
  
  return (
    <div style={{ padding: '20px' }}>
      <h2>Environment Configuration</h2>
      <pre>{JSON.stringify(config, null, 2)}</pre>
    </div>
  );
}

⚡ Performance Optimization

Code Splitting

jsx
import { Suspense, lazy } from 'react';

// Lazy loading component
const LazyComponent = lazy(() => import('./LazyComponent'));

function CodeSplittingExample() {
  const [showLazy, setShowLazy] = React.useState(false);
  
  return (
    <div>
      <h2>Code Splitting Demo</h2>
      <button onClick={() => setShowLazy(!showLazy)}>
        {showLazy ? 'Hide' : 'Show'} Lazy Component
      </button>
      
      {showLazy && (
        <Suspense fallback={<div>Loading...</div>}>
          <LazyComponent />
        </Suspense>
      )}
    </div>
  );
}

Resource Optimization

jsx
// Lazy image loading
function LazyImage({ src, alt, ...props }) {
  const [isLoaded, setIsLoaded] = React.useState(false);
  const [isInView, setIsInView] = React.useState(false);
  const imgRef = React.useRef();
  
  React.useEffect(() => {
    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          setIsInView(true);
          observer.disconnect();
        }
      },
      { threshold: 0.1 }
    );
    
    if (imgRef.current) {
      observer.observe(imgRef.current);
    }
    
    return () => observer.disconnect();
  }, []);
  
  return (
    <div ref={imgRef} style={{ minHeight: '200px', backgroundColor: '#f8f9fa' }}>
      {isInView && (
        <img
          src={src}
          alt={alt}
          onLoad={() => setIsLoaded(true)}
          style={{
            opacity: isLoaded ? 1 : 0,
            transition: 'opacity 0.3s',
            ...props.style
          }}
          {...props}
        />
      )}
    </div>
  );
}

🚀 Deployment Strategies

Static File Deployment

json
{
  "scripts": {
    "build": "react-scripts build",
    "deploy": "npm run build && cp -r build/* /var/www/html/",
    "deploy:s3": "aws s3 sync build/ s3://my-bucket --delete",
    "deploy:gh-pages": "gh-pages -d build"
  }
}

Nginx Configuration

nginx
server {
    listen 80;
    server_name example.com;
    root /var/www/html;
    index index.html;
    
    # Handle client-side routing
    location / {
        try_files $uri $uri/ /index.html;
    }
    
    # Static resource caching
    location /static/ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
    
    # API proxy
    location /api/ {
        proxy_pass http://localhost:3001;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Docker Deployment

dockerfile
# Dockerfile
FROM node:18-alpine as build

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
yaml
# docker-compose.yml
version: '3.8'
services:
  app:
    build: .
    ports:
      - "80:80"
    environment:
      - NODE_ENV=production
    restart: unless-stopped

CI/CD Configuration

yaml
# .github/workflows/deploy.yml
name: Deploy to Production

on:
  push:
    branches: [main]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v2
    
    - name: Setup Node.js
      uses: actions/setup-node@v2
      with:
        node-version: '18'
        cache: 'npm'
    
    - name: Install dependencies
      run: npm ci
    
    - name: Run tests
      run: npm test -- --coverage --watchAll=false
    
    - name: Build application
      run: npm run build
      env:
        REACT_APP_API_URL: ${{ secrets.API_URL }}
    
    - name: Deploy to S3
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: us-east-1
    
    - name: Sync to S3
      run: aws s3 sync build/ s3://my-bucket --delete
    
    - name: Invalidate CloudFront
      run: aws cloudfront create-invalidation --distribution-id ${{ secrets.CLOUDFRONT_ID }} --paths "/*"

📊 Monitoring and Analytics

Performance Monitoring

jsx
// Web Vitals monitoring
function performanceMonitoring() {
  // Simulating web-vitals library
  const getCLS = (onPerfEntry) => {
    // Cumulative Layout Shift
    if (onPerfEntry && onPerfEntry instanceof Function) {
      onPerfEntry({ name: 'CLS', value: 0.1 });
    }
  };
  
  const getFID = (onPerfEntry) => {
    // First Input Delay
    if (onPerfEntry && onPerfEntry instanceof Function) {
      onPerfEntry({ name: 'FID', value: 100 });
    }
  };
  
  const getFCP = (onPerfEntry) => {
    // First Contentful Paint
    if (onPerfEntry && onPerfEntry instanceof Function) {
      onPerfEntry({ name: 'FCP', value: 1500 });
    }
  };
  
  const getLCP = (onPerfEntry) => {
    // Largest Contentful Paint
    if (onPerfEntry && onPerfEntry instanceof Function) {
      onPerfEntry({ name: 'LCP', value: 2500 });
    }
  };
  
  const getTTFB = (onPerfEntry) => {
    // Time to First Byte
    if (onPerfEntry && onPerfEntry instanceof Function) {
      onPerfEntry({ name: 'TTFB', value: 200 });
    }
  };
  
  return { getCLS, getFID, getFCP, getLCP, getTTFB };
}

// Error boundary and error reporting
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false, error: null };
  }
  
  static getDerivedStateFromError(error) {
    return { hasError: true, error };
  }
  
  componentDidCatch(error, errorInfo) {
    // Send error to monitoring service
    this.reportError(error, errorInfo);
  }
  
  reportError = (error, errorInfo) => {
    // Simulating error report
    const errorReport = {
      message: error.message,
      stack: error.stack,
      componentStack: errorInfo.componentStack,
      timestamp: new Date().toISOString(),
      userAgent: navigator.userAgent,
      url: window.location.href
    };
    
    console.error('Error reported:', errorReport);
    
    // In production, send to error monitoring service
    // fetch('/api/errors', {
    //   method: 'POST',
    //   body: JSON.stringify(errorReport)
    // });
  };
  
  render() {
    if (this.state.hasError) {
      return (
        <div style={{ padding: '20px', textAlign: 'center' }}>
          <h2>Error Occurred</h2>
          <p>An error occurred in the application. Please refresh the page to try again.</p>
          <button onClick={() => window.location.reload()}>
            Refresh Page
          </button>
        </div>
      );
    }
    
    return this.props.children;
  }
}

Analytics Tool Integration

jsx
// Google Analytics integration
function useAnalytics() {
  React.useEffect(() => {
    // Simulating GA initialization
    if (process.env.NODE_ENV === 'production') {
      console.log('Google Analytics initialized');
    }
  }, []);
  
  const trackEvent = (action, category, label, value) => {
    if (process.env.NODE_ENV === 'production') {
      // gtag('event', action, {
      //   event_category: category,
      //   event_label: label,
      //   value: value
      // });
      console.log('Event tracked:', { action, category, label, value });
    }
  };
  
  const trackPageView = (path) => {
    if (process.env.NODE_ENV === 'production') {
      // gtag('config', 'GA_MEASUREMENT_ID', {
      //   page_path: path
      // });
      console.log('Page view tracked:', path);
    }
  };
  
  return { trackEvent, trackPageView };
}

// Analytics usage
function AnalyticsExample() {
  const { trackEvent, trackPageView } = useAnalytics();
  
  React.useEffect(() => {
    trackPageView('/analytics-example');
  }, [trackPageView]);
  
  const handleButtonClick = () => {
    trackEvent('click', 'button', 'analytics-example', 1);
  };
  
  return (
    <div style={{ padding: '20px' }}>
      <h2>Analytics Integration Example</h2>
      <button onClick={handleButtonClick}>
        Track Click Event
      </button>
    </div>
  );
}

🔐 Security Best Practices

Security Configuration

jsx
// Content Security Policy
function SecurityHeaders() {
  React.useEffect(() => {
    // In production, these should be set at the server level
    const securityHeaders = {
      'Content-Security-Policy': "default-src 'self'; script-src 'self' 'unsafe-inline'",
      'X-Frame-Options': 'DENY',
      'X-Content-Type-Options': 'nosniff',
      'Referrer-Policy': 'strict-origin-when-cross-origin'
    };
    
    console.log('Security headers should be set:', securityHeaders);
  }, []);
  
  return null;
}

// Sensitive data handling
function SecureDataHandling() {
  const [sensitiveData, setSensitiveData] = React.useState(null);
  
  const fetchSecureData = async () => {
    try {
      // Secure API call
      const token = localStorage.getItem('authToken');
      const response = await fetch('/api/secure-data', {
        headers: {
          'Authorization': `Bearer ${token}`,
          'Content-Type': 'application/json'
        }
      });
      
      if (!response.ok) {
        throw new Error('Unauthorized');
      }
      
      const data = await response.json();
      setSensitiveData(data);
    } catch (error) {
      console.error('Security error:', error);
      // Handle security error
    }
  };
  
  return (
    <div style={{ padding: '20px' }}>
      <h2>Secure Data Handling</h2>
      <button onClick={fetchSecureData}>
        Fetch Secure Data
      </button>
      {sensitiveData && (
        <div>Data fetched securely</div>
      )}
    </div>
  );
}

📝 Chapter Summary

Through this chapter, you should have mastered:

Build and Deployment

  • ✅ Production build optimization
  • ✅ Environment variable configuration
  • ✅ Static file deployment
  • ✅ Docker container deployment

Performance and Monitoring

  • ✅ Code splitting and lazy loading
  • ✅ Performance metrics monitoring
  • ✅ Error tracking and reporting
  • ✅ User behavior analytics

Best Practices

  1. Build Optimization: Enable compression, code splitting
  2. Caching Strategy: Set appropriate static resource caching
  3. Monitoring Alerts: Real-time application performance monitoring
  4. Security Protection: Set security headers, data encryption
  5. Continuous Deployment: Automated CI/CD pipeline

Continue Learning: Next Chapter - React vs Vanilla JavaScript

Content is for learning and research only.