Root-cause fix for "Failed to load module script: got text/html" on the live game. Assets are content-hash-named; the deploy used to `rm -rf` the web root before copying, so any browser/CDN holding a PREVIOUS index.html asked for chunks that no longer existed — nginx served the HTML fallback (200 text/html) and the module loader choked. Shipping 7 times in one session made stale-index clients common. - Step 3 now OVERLAYS (docker cp over the top, no rm), keeping old chunks alive as a grace window so a cached index.html still resolves. Prunes only files orphaned >7 days (current chunks get a fresh mtime every build) so /assets can't grow without bound. - Step 4 now fetches the entry chunk the LIVE index references and asserts it comes back as application/javascript — the index-only 200 check could not catch a broken chunk graph (a missing chunk IS a 200, as HTML). Verified it reports "entry chunk main-*.js -> application/javascript ✓". Note: nginx still serves index.html for any missing /assets file (masks a 404 as HTML). Fixing that (or adding Cache-Control: no-cache on index.html) touches the SHARED forum-nginx config that serves the other partly.party games, so it's left for a deliberate, John-signed-off change rather than done in passing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
73 lines
3.7 KiB
Bash
73 lines
3.7 KiB
Bash
#!/usr/bin/env bash
|
|
# =====================================================================
|
|
# BLOBBO — Deploy to partly.party/blobbo/
|
|
# =====================================================================
|
|
# Usage: bash deploy.sh (from the BLOBBO repo root)
|
|
#
|
|
# 1. npm run build (vite, base=/blobbo/)
|
|
# 2. rsync dist/ to VPS staging
|
|
# 3. OVERLAY into forum-nginx web root (keep old chunks; prune >7d orphans)
|
|
# 4. verify live index AND that its entry chunk serves as JavaScript
|
|
#
|
|
# Follows the GAMES/ deploy doctrine (see cratewars/deploy.sh template).
|
|
# Requirements: ssh humanjing@100.71.119.27 (tailscale), container forum-nginx.
|
|
# =====================================================================
|
|
set -euo pipefail
|
|
|
|
VPS="humanjing@100.71.119.27"
|
|
CONTAINER="forum-nginx"
|
|
REMOTE_WEB_ROOT="/usr/share/nginx/html/blobbo"
|
|
STAGING="/tmp/blobbo_deploy"
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
|
|
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.
|
|
# Custom models belong in the player's browser (IndexedDB) or in a decimated
|
|
# committed pack — never as an accident of local testing.
|
|
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] Overlaying container content (no wipe) ..."
|
|
# OVERLAY, don't 'rm -rf': assets are content-hash-named, so a browser (or CDN)
|
|
# holding a PREVIOUS index.html must still find the chunks it references, or the
|
|
# page dies with "expected a JS module, got text/html" (the missing chunk falls
|
|
# back to index.html). Copying over the top keeps old chunks alive as a grace
|
|
# window. Vite rewrites every current chunk each build, so their mtime is fresh;
|
|
# prune only files orphaned for >7 days so /assets can't grow without bound.
|
|
# ponytail: 7-day window is plenty for a browser cache; widen if a CDN caches index longer.
|
|
ssh "$VPS" "docker exec $CONTAINER sh -c 'mkdir -p ${REMOTE_WEB_ROOT:?}' \
|
|
&& docker cp $STAGING/. $CONTAINER:$REMOTE_WEB_ROOT/ \
|
|
&& docker exec $CONTAINER sh -c 'find ${REMOTE_WEB_ROOT}/assets -type f -mtime +7 -delete 2>/dev/null || true'"
|
|
|
|
echo "[4/4] Verifying live index + entry chunk ..."
|
|
BUST="$(date +%s)"
|
|
CODE_LIVE="$(curl -s -o /dev/null -w '%{http_code}' "https://partly.party/blobbo/?v=$BUST")"
|
|
echo " https://partly.party/blobbo/ -> HTTP $CODE_LIVE"
|
|
[ "$CODE_LIVE" = "200" ] || { echo " ✗ live index check failed"; exit 1; }
|
|
# The index-only check can't catch a broken chunk graph: a missing chunk is
|
|
# served as the HTML fallback (200 text/html), which is exactly the bug that
|
|
# bit us. Fetch the entry chunk the LIVE index references and confirm it comes
|
|
# back as JavaScript — the check that would actually have caught it.
|
|
MAIN="$(curl -s "https://partly.party/blobbo/?v=$BUST" | grep -oE '/blobbo/assets/main-[^"]+\.js' | head -1)"
|
|
[ -n "$MAIN" ] || { echo " ✗ no main chunk found in live index"; exit 1; }
|
|
CT="$(curl -s -o /dev/null -w '%{content_type}' "https://partly.party${MAIN}?v=$BUST")"
|
|
case "$CT" in
|
|
application/javascript*|text/javascript*) echo " entry chunk ${MAIN##*/} -> ${CT} ✓" ;;
|
|
*) echo " ✗ entry chunk ${MAIN##*/} served as '${CT}', not JS — broken deploy"; exit 1 ;;
|
|
esac
|
|
echo " ✓ deployed."
|