#!/usr/bin/env bash # 一键启动前后端开发服务 set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PIDS=() log() { echo ">>> $*"; } # 加载仓库根目录 .env(source 后可供 PORT / FRONTEND_PORT 使用) if [[ -f "$ROOT/.env" ]]; then set -a # shellcheck disable=SC1091 source "$ROOT/.env" set +a log "已加载 $ROOT/.env" elif [[ -f "$ROOT/.env.example" ]]; then log "未找到 .env,可执行: cp .env.example .env" fi BACKEND_PORT="${PORT:-8080}" FRONTEND_PORT="${FRONTEND_PORT:-5173}" # 结束指定端口上的进程(避免残留占用) free_port() { local port=$1 local pids pids=$(lsof -tiTCP:"$port" -sTCP:LISTEN 2>/dev/null || true) if [[ -n "${pids}" ]]; then log "端口 ${port} 已被占用,正在释放: ${pids}" # shellcheck disable=SC2086 kill ${pids} 2>/dev/null || true sleep 0.5 pids=$(lsof -tiTCP:"$port" -sTCP:LISTEN 2>/dev/null || true) if [[ -n "${pids}" ]]; then # shellcheck disable=SC2086 kill -9 ${pids} 2>/dev/null || true fi fi } cleanup() { trap - INT TERM EXIT echo "" log "正在停止前后端..." for pid in "${PIDS[@]:-}"; do if kill -0 "$pid" 2>/dev/null; then # 结束子进程树 pkill -P "$pid" 2>/dev/null || true kill "$pid" 2>/dev/null || true fi done free_port "$BACKEND_PORT" free_port "$FRONTEND_PORT" wait 2>/dev/null || true log "已全部停止" exit 0 } trap cleanup INT TERM # 检查依赖 if ! command -v go >/dev/null 2>&1; then echo "错误: 未找到 go,请先安装 Go" exit 1 fi if ! command -v npm >/dev/null 2>&1; then echo "错误: 未找到 npm,请先安装 Node.js" exit 1 fi # 首次安装前端依赖 if [[ ! -d "$ROOT/frontend/node_modules" ]]; then log "安装前端依赖..." (cd "$ROOT/frontend" && npm install) fi free_port "$BACKEND_PORT" free_port "$FRONTEND_PORT" log "启动后端 http://localhost:${BACKEND_PORT}" ( cd "$ROOT/backend" export PORT="$BACKEND_PORT" go run ./cmd/server ) & PIDS+=($!) # 等后端健康检查就绪(最多约 15 秒) for i in $(seq 1 30); do if curl -sf "http://127.0.0.1:${BACKEND_PORT}/health" >/dev/null 2>&1; then log "后端已就绪" break fi if ! kill -0 "${PIDS[0]}" 2>/dev/null; then echo "错误: 后端启动失败" cleanup fi sleep 0.5 done log "启动前端 http://localhost:${FRONTEND_PORT}" ( cd "$ROOT/frontend" npm run dev -- --host --port "$FRONTEND_PORT" ) & PIDS+=($!) echo "" log "========================================" log " 游戏皮肤分销系统 已启动" log " 前端: http://localhost:${FRONTEND_PORT}" log " 后端: http://localhost:${BACKEND_PORT}" log " 账号: admin / admin123" log " 按 Ctrl+C 停止全部服务" log "========================================" echo "" # 任一子进程退出则整体清理 wait -n 2>/dev/null || wait cleanup