The outage: deploy did rm -rf on the web root, THEN docker cp. Anyone loading in that window — or holding a cached index.html from before it — asked for a hashed bundle that no longer existed, and nginx answered with HTML: "Failed to load module script... MIME type of text/html". Exactly what got reported. Two changes: - Merge instead of swap. Hashed bundles never collide, so old builds' assets stay alive for stale HTML while the new index.html takes over. No gap, no orphaned caches. Disk is a few MB per deploy; prune by hand if it ever matters. - The verify step now follows the chain the browser follows: fetch the live index.html, extract the script src, and assert it serves as application/javascript. A 200 on the page proved nothing — the page was 200 all through the outage. Verified live: page → index-CmCk0pc0.js → application/javascript, and the game boots to the title screen on partly.party/toastsim. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
43 lines
2.0 KiB
Bash
Executable File
43 lines
2.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# TOASTSIM — deploy to partly.party/toastsim (games VPS, forum-nginx pattern).
|
|
# ./scripts/deploy.sh
|
|
# Build with subpath base → rsync to VPS staging → docker cp into web root → curl verify.
|
|
set -euo pipefail
|
|
|
|
VPS="humanjing@100.71.119.27"
|
|
CONTAINER="forum-nginx"
|
|
REMOTE_WEB_ROOT="/usr/share/nginx/html/toastsim"
|
|
STAGING="/tmp/toastsim_deploy"
|
|
REPO="$(cd "$(dirname "$0")/.." && pwd)"
|
|
|
|
echo "[1/4] Building (base=/toastsim/)..."
|
|
cd "$REPO"
|
|
./node_modules/.bin/tsc --noEmit
|
|
./node_modules/.bin/vite build --base=/toastsim/
|
|
|
|
echo "[2/4] Rsync dist → $VPS:$STAGING ..."
|
|
ssh "$VPS" "rm -rf '$STAGING' && mkdir -p '$STAGING'"
|
|
rsync -az dist/ "$VPS:$STAGING/"
|
|
|
|
echo "[3/4] Merge into $CONTAINER:$REMOTE_WEB_ROOT ..."
|
|
# ADDITIVE on purpose — no rm, no gap. The old flow (rm -rf, then docker cp)
|
|
# had a downtime window, and worse: any browser/CDN holding yesterday's
|
|
# index.html pointed at hashed bundles the rm had just deleted → the classic
|
|
# "module script served as text/html" outage. Hashed assets never collide, so
|
|
# merging keeps every old build's bundles alive for stale HTML while the new
|
|
# index.html takes over for everyone else. Disk cost is a few MB per deploy;
|
|
# prune assets/ older than ~30 days by hand if it ever matters.
|
|
ssh "$VPS" "docker exec '$CONTAINER' mkdir -p '$REMOTE_WEB_ROOT' \
|
|
&& docker cp '$STAGING/.' '$CONTAINER:$REMOTE_WEB_ROOT/'"
|
|
|
|
echo "[4/4] Verify the page AND the bundle it references..."
|
|
page=$(curl -s "https://partly.party/toastsim/?cb=$(date +%s)")
|
|
src=$(printf '%s' "$page" | grep -oE 'src="[^"]*\.js"' | sed 's/src="//;s/"//' | head -1)
|
|
[ -n "$src" ] || { echo "NOT DEPLOYED (no script tag in live index.html)"; exit 1; }
|
|
ctype=$(curl -so /dev/null -w '%{content_type}' "https://partly.party$src")
|
|
echo "https://partly.party/toastsim/ → script $src → $ctype"
|
|
case "$ctype" in
|
|
application/javascript*|text/javascript*) echo "done." ;;
|
|
*) echo "NOT DEPLOYED (bundle served as $ctype — stale index or missing asset)"; exit 1 ;;
|
|
esac
|