Archived: 2025-11-01 Reason: Completed - Performance optimizations implemented Status: Consolidated from planning and implementation documents Note: This document combines PERFORMANCE_OPTIMIZATION_PLAN.md and PERFORMANCE_OPTIMIZATION.md
Performance Optimization Plan for PiqueTickets Show Page¶
Based on the Lighthouse audit analysis and show page code review, here's a comprehensive plan to improve page load performance.
Executive Summary¶
Current Performance Issues: - First Contentful Paint: 6.7s (Target: <1.8s) - Largest Contentful Paint: 19.8s (Target: <2.5s) - Time to Interactive: 19.9s (Target: <3.4s) - Total payload: 3.4MB - Unused JavaScript: 2.4MB causing 2.8s delay
Expected Improvements: - 13+ second reduction in LCP through image optimization - 2.8 second reduction through JavaScript optimization - Significant improvement in Core Web Vitals scores
Critical Performance Issues Identified¶
1. Image Optimization (Highest Impact)¶
- Issue: Banner images and show background images not in modern formats (WebP/AVIF)
- Current: Large JPEG/PNG files served at full resolution from S3 without CDN optimization
- Impact: 7.4s potential LCP savings + 940ms from proper sizing + additional savings from Cloudflare CDN
- Priority: Critical
2. JavaScript Bundle Optimization¶
- Issue: 2.4MB unused JavaScript causing 2.8s delay
- Current: Large bundles with unused code
- Impact: 2.8s potential FCP/LCP savings
- Priority: High
3. Main Thread Blocking¶
- Issue: 3.7s of main thread work blocking interaction
- Current: Heavy JavaScript execution
- Impact: Poor Time to Interactive scores
- Priority: High
Implementation Plan¶
Phase 1: Image Optimization (Week 1)¶
Estimated Impact: 8+ second LCP improvement
1.1 API-Side WebP Conversion & S3 Optimization¶
- Location:
apps/api/- Image upload/processing endpoints and S3 integration - Implementation:
- Add WebP conversion on image upload for banner images AND show background images
- Generate multiple sizes (responsive images) for all image types
- Configure S3 bucket caching with proper headers
- Implement Cloudflare CDN in front of S3 for global image delivery
- Serve WebP with JPEG fallback
- Add image compression pipeline for all image assets
1.2 Frontend Image Optimization¶
- File:
apps/frontend/src/app/shows/[slug]/page.tsx(lines 304-311, 249) - Current Code:
// Banner image (line 304-311) <Image src={banner_image} alt={title} width={1200} height={600} className="w-full h-full object-cover" /> // Background image (line 249) style={{ backgroundImage: `url(${ticket_page_design?.[0]?.background_image})`, backgroundSize: 'cover', backgroundPosition: 'center', }} - Optimizations:
- Add
priorityprop for above-fold banner images - Convert background image to optimized Next.js Image component
- Implement responsive image sizes for both banner and background
- Add WebP format support with Cloudflare CDN URLs
- Optimize loading strategy with proper cache headers
Phase 2: JavaScript Optimization (Week 2)¶
Estimated Impact: 2.8 second improvement
2.1 Code Splitting & Lazy Loading¶
- Target: Component-level code splitting
- Components to optimize:
TicketCheckoutForm- Load only when neededVideoPlayer- Lazy load when video presentSocialShare- Defer loading- SEO components - Server-side only
2.2 Bundle Analysis & Tree Shaking¶
- Tools: Next.js Bundle Analyzer
- Focus: Remove unused dependencies
- Target Libraries:
- React Icons (tree-shake specific icons)
- Form libraries (lazy load)
- Third-party widgets
Phase 3: Core Web Vitals Optimization (Week 3)¶
Estimated Impact: Comprehensive performance improvement
3.1 Critical Resource Prioritization¶
- Hero image: Add
priorityloading - Above-fold content: Inline critical CSS
- Fonts: Optimize font loading strategy
3.2 Streaming & Progressive Enhancement¶
- Server Components: Maximize SSR usage
- Streaming: Implement progressive page loading
- Hydration: Selective client-side hydration
Technical Implementation Details¶
WebP Conversion Implementation¶
API Changes (Django) - Enhanced for S3 Integration¶
# Enhanced image processing pipeline with S3 optimization
from PIL import Image
import io
import boto3
from django.conf import settings
def convert_to_webp(image_file):
"""Convert uploaded image to WebP format with optimization"""
img = Image.open(image_file)
output = io.BytesIO()
img.save(output, format='WEBP', quality=85, optimize=True)
return output.getvalue()
def generate_responsive_sizes(image_file, image_type='banner'):
"""Generate multiple WebP sizes for responsive images"""
sizes = [400, 800, 1200, 1600]
webp_variants = {}
for size in sizes:
# Generate WebP at different sizes
webp_data = resize_and_convert(image_file, size)
webp_variants[size] = webp_data
# Upload to S3 with optimized caching headers
s3_key = f"images/{image_type}/{size}w/{image_file.name.replace('.jpg', '.webp').replace('.png', '.webp')}"
upload_to_s3_with_cache_headers(webp_data, s3_key)
return webp_variants
def resize_and_convert(image_file, target_width):
"""Resize image and convert to WebP"""
img = Image.open(image_file)
# Calculate height maintaining aspect ratio
aspect_ratio = img.height / img.width
target_height = int(target_width * aspect_ratio)
# Resize image
img_resized = img.resize((target_width, target_height), Image.Resampling.LANCZOS)
# Convert to WebP
output = io.BytesIO()
img_resized.save(output, format='WEBP', quality=85, optimize=True)
return output.getvalue()
def upload_to_s3_with_cache_headers(image_data, s3_key):
"""Upload image to S3 with optimized caching headers"""
s3_client = boto3.client('s3')
# Upload with cache optimization headers
s3_client.put_object(
Bucket=settings.AWS_STORAGE_BUCKET_NAME,
Key=s3_key,
Body=image_data,
ContentType='image/webp',
CacheControl='public, max-age=31536000, immutable', # 1 year cache
Metadata={
'optimized': 'true',
'format': 'webp'
}
)
return f"https://{settings.CLOUDFLARE_CDN_DOMAIN}/{s3_key}"
def process_show_images(show_instance):
"""Process both banner and background images for a show"""
processed_urls = {}
# Process banner image
if show_instance.banner_image:
banner_variants = generate_responsive_sizes(
show_instance.banner_image,
image_type='banners'
)
processed_urls['banner'] = banner_variants
# Process background image from ticket_page_design
if hasattr(show_instance, 'ticket_page_design') and show_instance.ticket_page_design:
for design in show_instance.ticket_page_design.all():
if design.background_image:
bg_variants = generate_responsive_sizes(
design.background_image,
image_type='backgrounds'
)
processed_urls['background'] = bg_variants
return processed_urls
# S3 Bucket Configuration for Django settings
AWS_S3_OBJECT_PARAMETERS = {
'CacheControl': 'max-age=86400', # Default 24 hour cache
}
# Cloudflare CDN settings
CLOUDFLARE_CDN_DOMAIN = 'cdn.piquetickets.com' # Custom domain pointing to Cloudflare
AWS_DEFAULT_ACL = 'public-read'
AWS_S3_FILE_OVERWRITE = False
Frontend Image Component Enhancement¶
// Optimized Image component for show banners with Cloudflare CDN
const OptimizedShowImage = ({ src, alt, title, priority = false }) => {
// Convert S3 URL to Cloudflare CDN URL with WebP format
const getCdnUrl = (originalUrl: string, width: number) => {
if (!originalUrl) return originalUrl;
// Replace S3 URL with Cloudflare CDN and add WebP format
const cdnUrl = originalUrl
.replace('s3.amazonaws.com/your-bucket', 'images.piquetickets.com')
.replace(/\.(jpg|jpeg|png)$/i, '.webp');
return `${cdnUrl}?w=${width}&q=85&f=webp`;
};
return (
<Image
src={getCdnUrl(src, 1200)}
alt={alt}
width={1200}
height={600}
sizes="(max-width: 768px) 400px, (max-width: 1200px) 800px, 1200px"
priority={priority}
className="w-full h-full object-cover"
placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/..."
/>
);
};
// Optimized Background Image Component
const OptimizedBackgroundImage = ({ backgroundImage, children }) => {
const [imageLoaded, setImageLoaded] = useState(false);
return (
<div className="relative">
{/* Next.js optimized background image */}
<Image
src={backgroundImage}
alt="Show background"
fill
className={`object-cover transition-opacity duration-300 ${imageLoaded ? 'opacity-100' : 'opacity-0'}`}
style={{ zIndex: -1 }}
onLoad={() => setImageLoaded(true)}
sizes="100vw"
quality={85}
/>
{/* Content overlay */}
<div className="relative z-10">
{children}
</div>
</div>
);
};
JavaScript Optimization Strategy¶
Dynamic Imports for Heavy Components¶
import dynamic from 'next/dynamic';
// Lazy load ticket form
const TicketCheckoutForm = dynamic(
() => import('@/components/Forms/tickets'),
{
loading: () => <TicketFormSkeleton />,
ssr: false
}
);
// Conditional video player loading
const VideoPlayer = dynamic(
() => import('@/components/VideoPlayer'),
{ ssr: false }
);
// Lazy load social sharing
const SocialShare = dynamic(
() => import('@/components/SocialShare'),
{
loading: () => <div className="h-8 bg-gray-200 animate-pulse rounded" />,
ssr: false
}
);
Bundle Splitting Configuration¶
// next.config.ts optimization
const nextConfig = {
experimental: {
optimizeCss: true,
},
images: {
formats: ['image/webp', 'image/avif'],
minimumCacheTTL: 60,
},
webpack: (config) => {
config.optimization.splitChunks = {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
chunks: 'all',
name: 'vendors',
},
common: {
name: 'common',
minChunks: 2,
chunks: 'all',
enforce: true,
},
},
};
return config;
},
};
export default nextConfig;
Show Page Optimization Implementation¶
Updated Show Page Structure with Cloudflare CDN Optimization¶
// apps/frontend/src/app/shows/[slug]/page.tsx - Key optimizations
export default async function ShowPage({ params }: Params) {
const slug = (await params).slug;
const show = await fetchShow(slug) as Show;
if (!show) {
notFound();
}
// ... existing logic ...
return (
<OptimizedBackgroundImage
backgroundImage={ticket_page_design?.[0]?.background_image}
>
<div
className="min-h-screen text-white flex flex-col items-center lg:p-2 md:p-2 p-0"
style={{
backgroundColor: ticket_page_design?.[0]?.primary_color,
}}
>
{/* Logo with CDN optimization */}
<div className='w-full text-white flex flex-col items-center lg:p-6 md:p-2 p-2'>
<Image
src="/logo.webp"
alt="Pique Tickets"
width={96}
height={96}
className="inline-block"
priority={true}
/>
</div>
<BackButton />
{/* Critical above-fold content */}
<div className="max-w-5xl w-full bg-white text-gray-900 shadow-lg overflow-hidden">
{/* Event Banner - Optimized with Cloudflare CDN */}
<div className="relative">
<OptimizedShowImage
src={banner_image}
alt={title}
title={title}
priority={true}
/>
</div>
{/* Event Details */}
<div className="p-4">
{/* Critical content first */}
<h1 className="text-2xl font-bold text-black">{title}</h1>
<p className="text-md text-gray-600">
{formatDateTime(start_time)} - {formatTime(end_time)}({time_zone_short})
</p>
<p className="text-black text-xl mt-4">{venue?.name} - {venue?.city}, {venue?.state}</p>
{/* Lazy-loaded components */}
{featured_video && (
<Suspense fallback={<div className="h-64 bg-gray-200 animate-pulse rounded" />}>
<VideoPlayer videoUrl={featured_video} />
</Suspense>
)}
{/* Producer image optimization */}
{producer && (
<div className="border-t border-t-gray-300 pt-4 pb-4 mb-4">
<h2 className="text-2xl font-bold mb-2 mt-2">Producer</h2>
<div className="flex items-center">
<div className="flex items-center space-x-4">
<Image
src={producer?.image || '/default-avatar.png'}
alt={producer?.name}
width={64}
height={64}
className="h-16 w-16 rounded-full object-cover"
loading="lazy"
/>
<div>
<h3 className="text-lg font-bold text-gray-800">
<a href={`/producers/${producer?.slug}`} className="font-bold mb-1">
{producer?.name}
</a>
</h3>
<p className="text-sm text-gray-500">
{producer?.shows_count || 0} shows hosted
</p>
</div>
</div>
</div>
</div>
)}
{/* Tickets Section - Lazy loaded */}
<div className="border-t border-gray-200">
<div id="ticket-checkout-form" className="w-full">
<h2 className="text-2xl font-bold mb-2 mt-2">Tickets</h2>
{!isSaleAvailable ? (
<p className="text-red-500">Ticket sales are no longer available.</p>
) : (
<Suspense fallback={<TicketFormSkeleton />}>
<TicketCheckoutForm
show_id={show.id}
tickets={tickets}
refund_policy={show?.refund_policy?.description}
/>
</Suspense>
)}
</div>
</div>
{/* Social Share - Lazy loaded */}
<Suspense fallback={<div className="h-8 bg-gray-200 animate-pulse rounded" />}>
<SocialShare
url={`https://piquetickets.com/shows/${slug}`}
title={title}
description={description}
/>
</Suspense>
</div>
</div>
</div>
</OptimizedBackgroundImage>
);
}
Risk Assessment & Mitigation¶
Technical Risks¶
| Risk | Probability | Impact | Mitigation |
|---|---|---|---|
| WebP compatibility issues | Low | Medium | Fallback to JPEG, progressive enhancement |
| Bundle splitting breaks functionality | Medium | High | Thorough testing, feature flags |
| API performance degradation | Medium | Medium | Async processing, CDN integration |
| SEO impact from lazy loading | Low | Medium | Proper SSR for critical content |
Deployment Strategy¶
- Feature Flags: Enable optimizations gradually
- A/B Testing: Compare performance before/after
- Monitoring: Real User Monitoring (RUM) implementation
- Rollback Plan: Quick revert mechanism
- Staging Testing: Full performance audit on staging
Success Metrics¶
Performance Targets¶
- First Contentful Paint: < 1.8s (currently 6.7s)
- Largest Contentful Paint: < 2.5s (currently 19.8s)
- Time to Interactive: < 3.4s (currently 19.9s)
- Total Blocking Time: < 200ms (currently 204ms)
- Bundle Size: < 1MB (currently 3.4MB)
- Lighthouse Performance Score: > 90 (currently poor)
Business Impact Targets¶
- Page Load Time: 70%+ improvement
- Bounce Rate: 15%+ reduction
- Conversion Rate: 10%+ improvement
- SEO Rankings: Improved Core Web Vitals scores
Monitoring Plan¶
- Week 1: Image optimization impact measurement
- Week 2: JavaScript optimization validation
- Week 3: Overall Core Web Vitals assessment
- Month 1: User experience metrics analysis
Implementation Timeline¶
Week 1: Image Optimization & S3 CDN Setup¶
- Implement WebP conversion in Django API for banner and background images
- Configure S3 bucket caching headers and Cloudflare CDN
- Add responsive image generation for all image types
- Update frontend Image components with CDN integration
- Convert CSS background images to optimized Next.js Image components
- Test WebP fallback mechanism
- Deploy to staging and measure impact
Week 2: JavaScript Optimization¶
- Implement dynamic imports for heavy components
- Configure bundle splitting
- Add loading skeletons
- Optimize third-party scripts
- Bundle analysis and cleanup
Week 3: Final Optimizations¶
- Implement critical CSS inlining
- Optimize font loading
- Add resource hints (preconnect, prefetch)
- Final performance testing
- Production deployment
Week 4: Monitoring & Refinement¶
- Set up performance monitoring
- Analyze real user metrics
- A/B test performance improvements
- Document learnings and next steps
Tools & Resources¶
Development Tools¶
- Next.js Bundle Analyzer:
npm install @next/bundle-analyzer - Lighthouse CI: Continuous performance monitoring
- Web Vitals: Real user monitoring
- Chrome DevTools: Performance profiling
API Tools¶
- Pillow (PIL): Python image processing
- django-imagekit: Django image optimization
- boto3: AWS S3 integration for image storage
- django-storages: S3 storage backend for Django
- WhiteNoise: Static file serving optimization
S3 & CDN Tools¶
- Cloudflare CDN: Global CDN for image delivery with superior performance
- AWS S3: Scalable image storage with cache headers
- Cloudflare Workers: Dynamic image resizing and optimization (optional)
Monitoring Tools¶
- Google PageSpeed Insights: Core Web Vitals tracking
- GTmetrix: Performance monitoring
- WebPageTest: Detailed performance analysis
S3 + Cloudflare CDN Configuration Steps¶
1. S3 Bucket Setup¶
# Create S3 bucket with proper permissions for Cloudflare access
aws s3 mb s3://piquetickets-images
aws s3api put-bucket-policy --bucket piquetickets-images --policy '{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "CloudflareReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::piquetickets-images/*"
}
]
}'
# Configure CORS for Cloudflare
aws s3api put-bucket-cors --bucket piquetickets-images --cors-configuration '{
"CORSRules": [
{
"AllowedOrigins": ["*"],
"AllowedMethods": ["GET"],
"AllowedHeaders": ["*"]
}
]
}'
2. Cloudflare CDN Setup¶
# Add custom domain to Cloudflare (via Cloudflare Dashboard)
# 1. Add images.piquetickets.com as CNAME to piquetickets-images.s3.amazonaws.com
# 2. Enable Cloudflare proxy (orange cloud)
# 3. Configure Page Rules for optimal caching:
# Page Rule: images.piquetickets.com/*
# Settings:
# - Cache Level: Cache Everything
# - Edge Cache TTL: 1 year
# - Browser Cache TTL: 1 year
# - Always Use HTTPS: On
3. Cloudflare Image Optimization¶
// Cloudflare Worker for dynamic image optimization (optional)
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
const url = new URL(request.url)
// Auto WebP conversion if browser supports it
const acceptHeader = request.headers.get('Accept') || ''
if (acceptHeader.includes('image/webp')) {
url.searchParams.set('f', 'webp')
}
// Responsive sizing based on query params
const width = url.searchParams.get('w')
if (width) {
url.searchParams.set('width', width)
}
const response = await fetch(url.toString())
// Cache for 1 year
const modifiedResponse = new Response(response.body, response)
modifiedResponse.headers.set('Cache-Control', 'public, max-age=31536000, immutable')
return modifiedResponse
}
4. Django Settings Configuration¶
# settings.py additions for S3 + Cloudflare optimization
AWS_STORAGE_BUCKET_NAME = 'piquetickets-images'
AWS_S3_REGION_NAME = 'us-east-1'
# Cloudflare CDN settings
CLOUDFLARE_CDN_DOMAIN = 'images.piquetickets.com'
# Optimized cache settings for S3
AWS_S3_OBJECT_PARAMETERS = {
'CacheControl': 'public, max-age=31536000, immutable', # 1 year cache
}
# Image optimization settings
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
STATICFILES_STORAGE = 'storages.backends.s3boto3.StaticS3Boto3Storage'
# Custom domain for image serving
AWS_S3_CUSTOM_DOMAIN = CLOUDFLARE_CDN_DOMAIN
Next Steps¶
- Immediate Action: Begin Phase 1 implementation with S3 + Cloudflare CDN setup
- Infrastructure Setup: Configure S3 bucket and Cloudflare CDN
- Team Alignment: Review plan with development team
- Environment Setup: Prepare staging environment for testing
- Baseline Establishment: Document current performance metrics
- Implementation Start: Begin WebP conversion and S3 integration development
This comprehensive plan provides a systematic approach to achieving significant performance improvements on the PiqueTickets show page, targeting image optimization with S3 + Cloudflare CDN integration as the highest-impact optimization, while maintaining a safe deployment strategy.
Why Cloudflare Over CloudFront?¶
Performance Benefits: - Faster Global Network: Cloudflare has 330+ edge locations with superior performance metrics - Superior Compression: Better Brotli compression and automatic optimization - Real-time Optimization: Dynamic image optimization without pre-processing - Cost Efficiency: More predictable pricing and better value
Technical Advantages: - Automatic WebP: Browser-based format detection and conversion - Polish Feature: Automatic image optimization and compression - Workers: Serverless functions for custom optimization logic - Better Caching: More aggressive and intelligent caching strategies# PiqueTickets Performance Optimization Implementation
Overview¶
This document details the implementation of comprehensive performance optimizations for the PiqueTickets show page, targeting a 13+ second reduction in load times and significant Core Web Vitals improvements.
🚀 Implemented Optimizations¶
1. Image Optimization Pipeline (✅ COMPLETED)¶
Location: apps/api/tickets/image_optimization.py
Features: - Enhanced WebP conversion with quality optimization - Responsive image generation (400px, 800px, 1200px, 1600px) - S3 integration with optimized caching headers (1-year cache) - Cloudflare CDN support for global delivery - Automatic aspect ratio preservation - Progressive enhancement with fallbacks
Expected Impact: 8+ second LCP improvement
2. Django API Enhancements (✅ COMPLETED)¶
Location: apps/api/tickets/models.py
Changes:
- Enhanced Show model with get_optimized_image_url() method
- Automatic image optimization on save
- Smart optimization triggers (published shows, new uploads)
- Robust error handling to prevent save failures
3. S3 + CDN Configuration (✅ COMPLETED)¶
Location: apps/api/brktickets/settings.py
Optimizations:
- Cloudflare CDN integration with CLOUDFLARE_CDN_DOMAIN support
- Optimized S3 object parameters (1-year immutable cache)
- Enhanced AWS S3 settings for performance
- Public read access for optimal delivery
4. Frontend Image Components (✅ COMPLETED)¶
Location: apps/frontend/src/components/OptimizedImage.tsx
Components:
- OptimizedImage: Base optimized image component
- OptimizedBannerImage: Hero image optimization with priority loading
- OptimizedBackgroundImage: CSS background → Next.js Image conversion
- OptimizedAvatarImage: Profile image optimization
Features: - Automatic CDN URL generation - WebP format enforcement with fallbacks - Responsive srcSet generation - Priority loading for above-fold content - Progressive loading with blur placeholders
5. Loading Skeletons (✅ COMPLETED)¶
Location: apps/frontend/src/components/LoadingSkeletons.tsx
Components:
- TicketFormSkeleton: Matches TicketCheckoutForm layout
- VideoPlayerSkeleton: Video component placeholder
- SocialShareSkeleton: Social sharing placeholder
- Various other skeleton components for smooth loading
6. Show Page Optimization (✅ COMPLETED)¶
Location: apps/frontend/src/app/shows/[slug]/page.tsx
Optimizations: - Dynamic imports for heavy components (TicketCheckoutForm, VideoPlayer, SocialShare) - Priority loading for banner images (LCP optimization) - Suspense boundaries with loading skeletons - Background image → optimized Image component conversion - Avatar image optimization for producer profiles
7. Next.js Bundle Optimization (✅ COMPLETED)¶
Location: apps/frontend/next.config.ts
Features:
- Advanced webpack chunk splitting (vendor, react, heavy-libs, common)
- Tree shaking improvements
- Bundle analyzer integration (npm run build:analyze)
- Enhanced image optimization settings (WebP, AVIF)
- Performance headers and caching strategies
- Console log removal in production
📊 Expected Performance Improvements¶
| Metric | Before | Target | Improvement |
|---|---|---|---|
| First Contentful Paint | 6.7s | <1.8s | 4.9s faster |
| Largest Contentful Paint | 19.8s | <2.5s | 17.3s faster |
| Time to Interactive | 19.9s | <3.4s | 16.5s faster |
| Total Blocking Time | 204ms | <200ms | Maintained |
| Bundle Size | 3.4MB | <1MB | 2.4MB reduction |
Key Optimizations Impact:¶
- Image Optimization: 8+ second LCP improvement
- JavaScript Optimization: 2.8 second improvement
- CDN Integration: Additional latency reduction globally
- Bundle Splitting: Improved caching and load times
🛠Usage Instructions¶
Running Bundle Analysis¶
Testing Optimizations¶
- Development:
npm run dev - Production Build:
npm run build - Performance Testing: Use Lighthouse, WebPageTest, or GTmetrix
Environment Variables¶
Add to your environment:
# CDN Configuration
CLOUDFLARE_CDN_DOMAIN=images.piquetickets.com
# S3 Configuration
S3_ENABLED=True
AWS_STORAGE_BUCKET_NAME=your-bucket-name
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
AWS_S3_REGION_NAME=us-east-1
🎯 Core Web Vitals Optimization¶
Largest Contentful Paint (LCP)¶
- ✅ Banner images load with
priority={true} - ✅ WebP format reduces file sizes by ~30%
- ✅ CDN reduces global latency
- ✅ Responsive images prevent oversized downloads
First Contentful Paint (FCP)¶
- ✅ Dynamic imports reduce initial bundle size
- ✅ Critical resources load first
- ✅ Bundle splitting improves caching
Cumulative Layout Shift (CLS)¶
- ✅ Image dimensions specified to prevent layout shifts
- ✅ Loading skeletons maintain layout during load
- ✅ Progressive enhancement prevents content jumps
🚀 Deployment Checklist¶
Before Deployment:¶
- Configure S3 bucket with public read access
- Set up Cloudflare CDN pointing to S3 bucket
- Add
CLOUDFLARE_CDN_DOMAINenvironment variable - Test image optimization in staging environment
- Run Lighthouse audit on staging
After Deployment:¶
- Monitor Core Web Vitals in production
- Test image loading across different devices
- Verify CDN cache hit rates
- Monitor bundle sizes and loading times
📈 Monitoring & Maintenance¶
Performance Monitoring:¶
- Google PageSpeed Insights: Monitor Core Web Vitals
- Real User Monitoring: Track actual user performance
- Bundle Analysis: Regular size monitoring
- CDN Analytics: Cache hit rates and global performance
Image Optimization Maintenance:¶
- Images are automatically optimized on upload
- Monitor S3 storage costs and CDN bandwidth
- Periodically review and update responsive breakpoints
- Consider implementing dynamic image resizing with Cloudflare Workers
🔧 Troubleshooting¶
Image Loading Issues:¶
- Check CDN domain configuration
- Verify S3 bucket permissions
- Test fallback to original URLs
Bundle Size Issues:¶
- Run
npm run build:analyzeto identify large dependencies - Review dynamic imports and lazy loading
- Check for duplicate dependencies
Performance Regression:¶
- Compare Lighthouse scores before/after changes
- Monitor bundle sizes in CI/CD
- Use performance budgets in webpack
🎉 Success Metrics¶
The implementation targets these performance improvements: - 70%+ reduction in page load time - 15%+ reduction in bounce rate - 10%+ improvement in conversion rate - Lighthouse Performance Score > 90
Next Steps¶
- Deploy to staging and run comprehensive performance tests
- A/B test performance improvements against current implementation
- Monitor real user metrics post-deployment
- Iterate based on performance data and user feedback
This optimization implementation follows industry best practices and targets the specific performance issues identified in the Lighthouse audit.