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 -- --analyzeEnvironment 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.0jsx
// 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-stoppedCI/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
- Build Optimization: Enable compression, code splitting
- Caching Strategy: Set appropriate static resource caching
- Monitoring Alerts: Real-time application performance monitoring
- Security Protection: Set security headers, data encryption
- Continuous Deployment: Automated CI/CD pipeline
Continue Learning: Next Chapter - React vs Vanilla JavaScript