- 新增双升(DoubleUp)完整实现:引擎 double-up-core.ts / double-up.ts、牌桌 UI DoubleUpBoard.tsx、单测与 E2E - 甩牌跟牌修复:validateFollow 新增 mixed 分支,甩牌后其他家可正常跟单张同花色牌 - start.sh:PORT=5173 单端口一键启动(Koa 同时 serve 页面+/api+/socket.io),浏览器直连无需 Vite 代理 - 玩家名 server 权威化(join 时写入 G.playerNames);LobbyRoomList 支持 fixedSeats(双升固定 4 人) - 文档:新增 dev-log/14、更新 dev-log README 索引与进度、更新根 README 启动/部署说明 - .gitignore 忽略根目录 data/*.db 运行时 SQLite
118 lines
4.1 KiB
Bash
Executable File
118 lines
4.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# tts-like 单端口启动脚本
|
||
#
|
||
# 用法: ./start.sh
|
||
# 或: bash start.sh
|
||
#
|
||
# 行为:
|
||
# 1. 加载 nvm + 启用 pnpm
|
||
# 2. node_modules 缺失时自动 pnpm install
|
||
# 3. 以 PORT=5173 启动 boardgame.io relay server(Koa)
|
||
# —— Koa 单端口同时 serve 前端页面(apps/web/dist) + /api REST + /socket.io WS,
|
||
# 浏览器直连 :5173 即可,无需 Vite 代理(见 CODEBUDDY.md「统一端口」一节)。
|
||
# —— 前置要求:apps/web/dist 已存在(即跑过 pnpm --filter @tts-like/web build)。
|
||
# 若缺失,本脚本会自动先 build 一次。
|
||
#
|
||
# 启动后打开 http://localhost:5173
|
||
# 该模式适合用 frp / Cloudflare Tunnel 直接映射 5173 端口对外(客户端零配置)。
|
||
#
|
||
# Ctrl-C 干净退出(连带 kill tsx 派生进程,避免残留占端口)。
|
||
|
||
set -euo pipefail
|
||
|
||
# ---------- 1. 加载 nvm + pnpm ----------
|
||
export NVM_DIR="$HOME/.nvm"
|
||
if [ -s "$NVM_DIR/nvm.sh" ]; then
|
||
# shellcheck disable=SC1091
|
||
. "$NVM_DIR/nvm.sh"
|
||
fi
|
||
|
||
if ! command -v node >/dev/null 2>&1; then
|
||
echo "✗ 未找到 node。请先装 nvm + Node 22:"
|
||
echo " curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash"
|
||
echo " nvm install 22"
|
||
exit 1
|
||
fi
|
||
echo "✓ node $(node -v)"
|
||
|
||
if ! command -v pnpm >/dev/null 2>&1; then
|
||
echo "→ 启用 pnpm (corepack)..."
|
||
corepack enable >/dev/null 2>&1 || true
|
||
fi
|
||
echo "✓ pnpm $(pnpm --version)"
|
||
|
||
# 切到项目根目录(脚本所在目录)
|
||
cd "$(dirname "$0")"
|
||
|
||
# ---------- 2. 依赖检查 ----------
|
||
if [ ! -d node_modules ]; then
|
||
echo "→ 首次运行,安装依赖(可能要 1-2 分钟)..."
|
||
pnpm install
|
||
fi
|
||
echo "✓ 依赖就绪"
|
||
|
||
# ---------- 3. 确保前端已构建(单端口 serve 需要 dist) ----------
|
||
if [ ! -f apps/web/dist/index.html ]; then
|
||
echo "→ apps/web/dist 不存在,先 build 前端(生产静态产物)..."
|
||
pnpm --filter @tts-like/web build
|
||
fi
|
||
echo "✓ 前端产物就绪 (apps/web/dist)"
|
||
|
||
# ---------- 4. 清理可能残留的旧进程(5173 / 8000) ----------
|
||
for port in 5173 8000; do
|
||
if command -v ss >/dev/null 2>&1 && ss -ltn "sport = :$port" 2>/dev/null | grep -q ":$port"; then
|
||
echo "⚠ 端口 $port 已被占用,尝试清理..."
|
||
(command -v lsof >/dev/null 2>&1 && lsof -ti:"$port" | xargs -r kill) 2>/dev/null || true
|
||
fi
|
||
done
|
||
|
||
# ---------- 5. 以 PORT=5173 启动 server(单端口,serve 页面 + API + WS) ----------
|
||
echo ""
|
||
echo "→ 启动 server(PORT=5173,单端口模式)..."
|
||
export PORT=5173
|
||
setsid pnpm --filter @tts-like/server dev &
|
||
SERVER_PID=$!
|
||
PIDS=("$SERVER_PID")
|
||
|
||
cleanup() {
|
||
echo ""
|
||
echo "→ 退出,清理子进程..."
|
||
for pid in "${PIDS[@]:-}"; do
|
||
[ -n "$pid" ] || continue
|
||
kill -TERM -"$pid" 2>/dev/null || kill "$pid" 2>/dev/null || true
|
||
done
|
||
for pid in "${PIDS[@]:-}"; do
|
||
[ -n "$pid" ] && kill -9 "$pid" 2>/dev/null || true
|
||
done
|
||
wait 2>/dev/null || true
|
||
echo "✓ 已退出"
|
||
}
|
||
trap cleanup EXIT INT TERM
|
||
|
||
# 等 server 起来(看到 listening 才继续)
|
||
echo "→ 等待 server 就绪(:5173/healthz)..."
|
||
for i in $(seq 1 30); do
|
||
if curl -sf http://localhost:5173/healthz >/dev/null 2>&1; then
|
||
echo "✓ server 就绪"
|
||
break
|
||
fi
|
||
if ! kill -0 "$SERVER_PID" 2>/dev/null; then
|
||
echo "✗ server 进程已退出,启动失败。检查上方日志(常见于 :5173 端口被占用)。"
|
||
exit 1
|
||
fi
|
||
sleep 0.5
|
||
done
|
||
|
||
echo ""
|
||
echo "════════════════════════════════════════════════════════════════"
|
||
echo " tts-like 已启动(单端口模式)"
|
||
echo " 单端口: http://localhost:5173 (页面 + /api + /socket.io)"
|
||
echo " 健康: http://localhost:5173/healthz"
|
||
echo ""
|
||
echo " 局域网/公网映射: 直接映射 5173 端口即可(frp / Cloudflare Tunnel)"
|
||
echo " Ctrl-C 退出"
|
||
echo "════════════════════════════════════════════════════════════════"
|
||
echo ""
|
||
|
||
wait "$SERVER_PID" 2>/dev/null || true
|