#!/usr/bin/env bash # ===================================================================== # BLOBBO — Deploy to monsterrobot.games/games/blobbo/ (+ legacy partly.party) # ===================================================================== # Usage: bash deploy.sh (from the BLOBBO repo root) # # 1. npm run build (vite, RELATIVE base './' — one build works at any mount) # 2. rsync dist/ to VPS staging (for the docker-cp leg) # 3. publish: # · monsterrobot.games — rsync into the HOST bind-mount source (canonical, # persistent). The mount is READ-ONLY inside the container, so we write # the host dir, not `docker cp`. # · partly.party — best-effort `docker cp` into the container-internal # legacy dir (ephemeral; not the real home). # Both OVERLAY (no delete) so a cached index.html keeps finding its chunks; # only >7d-orphaned chunks are pruned. # 4. verify each live index AND that its entry chunk serves as JavaScript. # # Requirements: ssh humanjing@100.71.119.27 (tailscale), container forum-nginx. # ===================================================================== set -euo pipefail VPS="humanjing@100.71.119.27" CONTAINER="forum-nginx" STAGING="/tmp/blobbo_deploy" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" # canonical: the arcade. HOST path (bind-mounted read-only into forum-nginx at # /usr/share/nginx/html/games-lander) — so we write the host dir directly. HOST_ROOT="/home/humanjing/monsterrobot.games/games/blobbo" SITE_CANON="https://monsterrobot.games/games/blobbo/" # legacy: container-internal (not a bind mount) — kept live as a courtesy. LEGACY_ROOT="/usr/share/nginx/html/blobbo" SITE_LEGACY="https://partly.party/blobbo/" echo "[1/4] Building ..." cd "$SCRIPT_DIR" npm run build # Guard: scripts/stage-farm-assets.sh copies ~43MB of raw farm GLBs into # public/ for local Workshop testing, and vite copies public/ straight into # dist/. Shipping those means every player downloads 43MB of background props. DIST_KB="$(du -sk dist | cut -f1)" if [ "$DIST_KB" -gt 10240 ]; then echo " ✗ dist/ is ${DIST_KB}KB (>10MB). Staged farm assets leaked into the build?" echo " Run: rm -rf public/assets/meshes && npm run build" exit 1 fi echo " dist/ is ${DIST_KB}KB — ok" echo "[2/4] Syncing dist/ to VPS staging ..." ssh "$VPS" "rm -rf '$STAGING' && mkdir -p '$STAGING'" rsync -az --exclude='.DS_Store' "$SCRIPT_DIR/dist/" "$VPS:$STAGING/" echo "[3/4] Publishing ..." # --- monsterrobot.games (canonical, host dir, rsync OVERLAY) --- # No --delete: a browser/CDN holding a previous index.html must still find the # content-hashed chunks it references, or the module loader chokes on the HTML # fallback. Vite rewrites current chunks each build (fresh mtime); prune only # files orphaned >7d so /assets can't grow without bound. echo " → monsterrobot.games (host $HOST_ROOT)" ssh "$VPS" "mkdir -p '$HOST_ROOT/assets'" rsync -az --exclude='.DS_Store' "$SCRIPT_DIR/dist/" "$VPS:$HOST_ROOT/" ssh "$VPS" "find '$HOST_ROOT/assets' -type f -mtime +7 -delete 2>/dev/null || true" # --- partly.party (legacy, container-internal, best-effort) --- echo " → partly.party (container $LEGACY_ROOT, best-effort)" ssh "$VPS" "docker exec $CONTAINER sh -c 'mkdir -p $LEGACY_ROOT' \ && docker cp $STAGING/. $CONTAINER:$LEGACY_ROOT/ \ && docker exec $CONTAINER sh -c 'find $LEGACY_ROOT/assets -type f -mtime +7 -delete 2>/dev/null || true'" \ || echo " (legacy partly.party copy failed — non-fatal; monsterrobot.games is canonical)" echo "[4/4] Verifying each live index + entry chunk ..." BUST="$(date +%s)" verify_site() { local url="$1" code main ct code="$(curl -s -o /dev/null -w '%{http_code}' "${url}?v=$BUST")" # relative-base index references chunks as ./assets/... — resolve against url main="$(curl -s "${url}?v=$BUST" | grep -oE '(\./|/)?assets/main-[^"]+\.js' | head -1)" if [ "$code" = "200" ] && [ -n "$main" ]; then ct="$(curl -s -o /dev/null -w '%{content_type}' "${url}${main#./}?v=$BUST")" case "$ct" in application/javascript*|text/javascript*) echo " ✓ ${url} (index 200, entry chunk ${ct})"; return 0 ;; *) echo " ✗ ${url} entry chunk served as '${ct}', not JS"; return 1 ;; esac fi echo " ✗ ${url} -> HTTP ${code}, main chunk '${main:-none}'"; return 1 } verify_site "$SITE_CANON" || { echo " ✗ CANONICAL (monsterrobot.games) deploy failed"; exit 1; } verify_site "$SITE_LEGACY" || echo " (legacy partly.party check failed — non-fatal)" echo " ✓ deployed — monsterrobot.games/games/blobbo/ is live."