everytab/pipeline/06_frontend/deploy.sh

130 lines
4 KiB
Bash
Executable file

#!/usr/bin/env bash
set -euo pipefail
# Deploy frontend to S3 and invalidate CloudFront cache.
usage() {
cat <<'EOF'
Usage: ./deploy.sh --total-bundles N [OPTIONS]
Required:
--total-bundles N Number of bundle files (from bundle_gen output)
Optional:
--site-bucket NAME S3 bucket (default: everytab-site)
--distribution-id ID CloudFront distribution ID (default: auto-detect)
--skip-invalidation Don't invalidate CloudFront cache
--help Show this help message
Example:
./deploy.sh --total-bundles 779
./deploy.sh --total-bundles 779 --distribution-id E14S2BLD6PG2XZ
EOF
exit 0
}
TOTAL_BUNDLES=""
SITE_BUCKET="everytab-site"
DIST_ID=""
SKIP_INVALIDATION=false
if [ $# -eq 0 ]; then usage; fi
while [ $# -gt 0 ]; do
case "$1" in
--help) usage ;;
--total-bundles) TOTAL_BUNDLES="$2"; shift 2 ;;
--site-bucket) SITE_BUCKET="$2"; shift 2 ;;
--distribution-id) DIST_ID="$2"; shift 2 ;;
--skip-invalidation) SKIP_INVALIDATION=true; shift ;;
*) echo "Unknown option: $1"; usage ;;
esac
done
if [ -z "$TOTAL_BUNDLES" ]; then
echo "ERROR: --total-bundles is required"
exit 1
fi
# Find frontend directory (relative to this script)
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
FRONTEND_DIR="$SCRIPT_DIR/../../frontend"
if [ ! -f "$FRONTEND_DIR/index.html" ]; then
echo "ERROR: frontend/index.html not found at $FRONTEND_DIR"
exit 1
fi
echo "=== Frontend Deploy ==="
echo "Total bundles: $TOTAL_BUNDLES"
echo "S3 bucket: $SITE_BUCKET"
echo ""
# Build into temp directory
TMPDIR=$(mktemp -d)
cp "$FRONTEND_DIR/index.html" "$TMPDIR/index.html"
cp "$FRONTEND_DIR/site.js" "$TMPDIR/site.js"
cp "$FRONTEND_DIR/bot.html" "$TMPDIR/bot.html"
cp "$FRONTEND_DIR/about.html" "$TMPDIR/about.html"
# Inject TOTAL_BUNDLES
sed -i "s/const TOTAL_BUNDLES = [0-9]*/const TOTAL_BUNDLES = ${TOTAL_BUNDLES}/" "$TMPDIR/index.html"
echo "Injected TOTAL_BUNDLES = $TOTAL_BUNDLES"
# Minify JS (strip comments + whitespace, keep variable names)
if command -v esbuild &>/dev/null; then
esbuild "$TMPDIR/site.js" --minify --outfile="$TMPDIR/site.js" --allow-overwrite
echo "Minified site.js"
else
echo "Warning: esbuild not found, deploying unminified JS"
fi
# Upload
echo "Uploading to s3://$SITE_BUCKET/..."
aws s3 cp "$TMPDIR/index.html" "s3://$SITE_BUCKET/" --content-type "text/html"
aws s3 cp "$TMPDIR/site.js" "s3://$SITE_BUCKET/" --content-type "application/javascript"
aws s3 cp "$TMPDIR/bot.html" "s3://$SITE_BUCKET/" --content-type "text/html"
aws s3 cp "$TMPDIR/about.html" "s3://$SITE_BUCKET/" --content-type "text/html"
echo "Uploaded 4 files"
rm -rf "$TMPDIR"
# Clean up stale bundles from previous runs
echo "Cleaning stale bundles above $TOTAL_BUNDLES..."
STALE=$(aws s3api list-objects-v2 --bucket "$SITE_BUCKET" --prefix "tabs/" --query "Contents[].Key" --output text \
| tr '\t' '\n' \
| while read -r key; do
num=$(echo "$key" | grep -oP '\d+' || true)
if [ -n "$num" ] && [ "$((10#$num))" -ge "$TOTAL_BUNDLES" ]; then
echo "$key"
fi
done)
if [ -n "$STALE" ]; then
STALE_COUNT=$(echo "$STALE" | wc -l)
echo "Deleting $STALE_COUNT stale bundles..."
echo "$STALE" | while read -r key; do
aws s3 rm "s3://$SITE_BUCKET/$key" --quiet
done
echo "Deleted $STALE_COUNT stale bundles"
else
echo "No stale bundles found"
fi
# Invalidate CloudFront
if ! $SKIP_INVALIDATION; then
if [ -z "$DIST_ID" ]; then
DIST_ID=$(aws cloudfront list-distributions --query "DistributionList.Items[?Aliases.Items[?contains(@,'everytab')]].Id" --output text 2>/dev/null || true)
fi
if [ -n "$DIST_ID" ]; then
echo "Invalidating CloudFront $DIST_ID..."
aws cloudfront create-invalidation --distribution-id "$DIST_ID" --paths "/index.html" "/site.js" "/bot.html" "/about.html" > /dev/null
echo "Invalidation submitted"
else
echo "Warning: no CloudFront distribution found, skipping invalidation"
fi
fi
echo ""
echo "=== Deploy Complete ==="