← back to Watches

performance-optimize.sh

223 lines

#!/bin/bash

###############################################################################
# OMEGA WATCHES - PERFORMANCE OPTIMIZATION SCRIPT
# Implements: WebP conversion, pre-compression, build optimization
###############################################################################

set -e

PROJECT_DIR="/root/Projects/watches"
DIST_DIR="$PROJECT_DIR/dist"
PUBLIC_DIR="$PROJECT_DIR/public"

echo "╔════════════════════════════════════════════════════════════════╗"
echo "║        OMEGA WATCHES - PERFORMANCE OPTIMIZATION               ║"
echo "╚════════════════════════════════════════════════════════════════╝"
echo ""

# Step 1: Build optimized production bundle
echo "🔨 Step 1/6: Building optimized production bundle..."
cd "$PROJECT_DIR"
npm run build

echo ""
echo "📊 Bundle Analysis:"
du -sh "$DIST_DIR"
echo ""
find "$DIST_DIR" -type f -name "*.js" -exec du -h {} \; | sort -hr | head -10

# Step 2: Convert images to WebP (if any exist)
echo ""
echo "🖼️  Step 2/6: Converting images to WebP format..."

convert_to_webp() {
    local dir=$1
    if [ -d "$dir" ]; then
        find "$dir" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) | while read img; do
            webp_name="${img%.*}.webp"
            if [ ! -f "$webp_name" ]; then
                echo "  Converting: $(basename $img) -> $(basename $webp_name)"
                cwebp -q 85 "$img" -o "$webp_name" 2>/dev/null || echo "    (skipped)"
            fi
        done
    fi
}

convert_to_webp "$DIST_DIR/assets"
convert_to_webp "$PUBLIC_DIR/icons"

# Step 3: Pre-compress static assets with Brotli
echo ""
echo "🗜️  Step 3/6: Pre-compressing assets with Brotli..."

compress_files() {
    local dir=$1
    find "$dir" -type f \( -name "*.js" -o -name "*.css" -o -name "*.html" -o -name "*.json" -o -name "*.svg" \) | while read file; do
        if [ ! -f "${file}.br" ]; then
            echo "  Brotli: $(basename $file)"
            brotli -f -k -q 11 "$file"
        fi

        if [ ! -f "${file}.gz" ]; then
            echo "  Gzip: $(basename $file)"
            gzip -f -k -9 "$file"
        fi
    done
}

compress_files "$DIST_DIR"

# Step 4: Generate performance manifest
echo ""
echo "📋 Step 4/6: Generating performance manifest..."

cat > "$DIST_DIR/performance-manifest.json" <<EOF
{
  "optimized": true,
  "timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")",
  "optimizations": [
    "Brotli compression (level 11)",
    "Gzip compression (level 9)",
    "WebP image conversion",
    "Code splitting (4 chunks)",
    "Tree shaking",
    "Minification (Terser)",
    "CSS minification",
    "Asset versioning (cache-busting)",
    "Pre-compressed static files"
  ],
  "bundle_sizes": {
    "total": "$(du -sh $DIST_DIR | cut -f1)",
    "js": "$(find $DIST_DIR -name '*.js' -exec du -ch {} + | grep total | cut -f1)",
    "css": "$(find $DIST_DIR -name '*.css' -exec du -ch {} + | grep total | cut -f1)",
    "compressed": "$(find $DIST_DIR -name '*.br' -exec du -ch {} + | grep total | cut -f1)"
  }
}
EOF

# Step 5: Create resource hints file
echo ""
echo "🔗 Step 5/6: Creating resource hints..."

cat > "$DIST_DIR/.htaccess" <<'EOF'
# Apache Performance Configuration

# Enable Brotli compression
<IfModule mod_brotli.c>
    AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/xml text/css text/javascript application/javascript application/json
</IfModule>

# Enable Gzip compression
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/json application/xml+rss
</IfModule>

# Serve pre-compressed files
<IfModule mod_rewrite.c>
    RewriteEngine On

    # Serve Brotli files if available
    RewriteCond %{HTTP:Accept-Encoding} br
    RewriteCond %{REQUEST_FILENAME}.br -f
    RewriteRule ^(.*)$ $1.br [L]

    # Serve Gzip files if available
    RewriteCond %{HTTP:Accept-Encoding} gzip
    RewriteCond %{REQUEST_FILENAME}.gz -f
    RewriteRule ^(.*)$ $1.gz [L]
</IfModule>

# Cache control
<IfModule mod_expires.c>
    ExpiresActive On

    # HTML (no cache)
    ExpiresByType text/html "access plus 0 seconds"

    # CSS and JavaScript (1 year)
    ExpiresByType text/css "access plus 1 year"
    ExpiresByType application/javascript "access plus 1 year"

    # Images (1 year)
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/png "access plus 1 year"
    ExpiresByType image/webp "access plus 1 year"
    ExpiresByType image/svg+xml "access plus 1 year"

    # Fonts (1 year)
    ExpiresByType font/woff2 "access plus 1 year"
    ExpiresByType font/woff "access plus 1 year"
</IfModule>

# Security headers
<IfModule mod_headers.c>
    Header set X-Content-Type-Options "nosniff"
    Header set X-Frame-Options "SAMEORIGIN"
    Header set X-XSS-Protection "1; mode=block"

    # Set proper MIME types for compressed files
    <FilesMatch "\.js\.br$">
        Header set Content-Type "application/javascript"
        Header set Content-Encoding "br"
    </FilesMatch>

    <FilesMatch "\.css\.br$">
        Header set Content-Type "text/css"
        Header set Content-Encoding "br"
    </FilesMatch>

    <FilesMatch "\.js\.gz$">
        Header set Content-Type "application/javascript"
        Header set Content-Encoding "gzip"
    </FilesMatch>

    <FilesMatch "\.css\.gz$">
        Header set Content-Type "text/css"
        Header set Content-Encoding "gzip"
    </FilesMatch>
</IfModule>
EOF

# Step 6: Run Lighthouse audit
echo ""
echo "🔍 Step 6/6: Performance summary..."

BEFORE_SIZE=$(du -sb "$DIST_DIR" | cut -f1)
AFTER_SIZE=$(find "$DIST_DIR" -name "*.br" -exec du -b {} + | awk '{sum+=$1} END {print sum}')
COMPRESSION_RATIO=$(echo "scale=1; (1 - $AFTER_SIZE / $BEFORE_SIZE) * 100" | bc)

echo ""
echo "════════════════════════════════════════════════════════════════"
echo "                    OPTIMIZATION RESULTS                         "
echo "════════════════════════════════════════════════════════════════"
echo ""
echo "Bundle Size (uncompressed): $(numfmt --to=iec $BEFORE_SIZE)"
echo "Bundle Size (Brotli):       $(numfmt --to=iec $AFTER_SIZE)"
echo "Compression Ratio:          ${COMPRESSION_RATIO}%"
echo ""
echo "Files Optimized:"
echo "  JavaScript files:  $(find $DIST_DIR -name '*.js' | wc -l)"
echo "  CSS files:         $(find $DIST_DIR -name '*.css' | wc -l)"
echo "  Brotli files:      $(find $DIST_DIR -name '*.br' | wc -l)"
echo "  Gzip files:        $(find $DIST_DIR -name '*.gz' | wc -l)"
echo "  WebP images:       $(find $DIST_DIR -name '*.webp' 2>/dev/null | wc -l)"
echo ""
echo "Performance Features:"
echo "  ✓ Code splitting (4 chunks)"
echo "  ✓ Tree shaking enabled"
echo "  ✓ Minification (Terser, 2 passes)"
echo "  ✓ Brotli compression (level 11)"
echo "  ✓ Gzip compression (level 9)"
echo "  ✓ CSS minification"
echo "  ✓ Asset versioning (cache-busting)"
echo "  ✓ Pre-compressed files"
echo "  ✓ WebP image support"
echo ""
echo "Next Steps:"
echo "  1. Restart server: pm2 restart omega-watches"
echo "  2. Test performance: ./lighthouse-test.sh"
echo "  3. Monitor: curl http://45.61.58.125:7600/api/metrics"
echo ""
echo "════════════════════════════════════════════════════════════════"