58 lines
1.9 KiB
Bash
Executable File
58 lines
1.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# 同时启动后端(FastAPI :8000)与前端(Vite :5173)。
|
||
# 端口可用 BACKEND_PORT / FRONTEND_PORT 覆盖。
|
||
set -euo pipefail
|
||
|
||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||
BACKEND_PORT="${BACKEND_PORT:-8000}"
|
||
FRONTEND_PORT="${FRONTEND_PORT:-5173}"
|
||
|
||
if [[ ! -x "$ROOT_DIR/backend/.venv/bin/uvicorn" ]]; then
|
||
echo "尚未初始化,请先运行 ./scripts/init.sh" >&2
|
||
exit 1
|
||
fi
|
||
if [[ ! -f "$ROOT_DIR/data/math.db" ]]; then
|
||
echo "数据库不存在,请先运行 ./scripts/init.sh" >&2
|
||
exit 1
|
||
fi
|
||
if ! command -v node >/dev/null 2>&1; then
|
||
echo "未找到 Node.js,前端无法启动。请安装 Node 20.19+ / 22.12+(或先只跑后端:cd backend && .venv/bin/uvicorn main:app --reload)" >&2
|
||
exit 1
|
||
fi
|
||
|
||
# 端口占用早失败,避免 Vite 报一堆堆栈
|
||
require_free_port() {
|
||
local port="$1" name="$2"
|
||
command -v lsof >/dev/null 2>&1 || return 0
|
||
if lsof -nP -iTCP:"$port" -sTCP:LISTEN >/dev/null 2>&1; then
|
||
echo "端口 $port($name)已被占用:" >&2
|
||
lsof -nP -iTCP:"$port" -sTCP:LISTEN >&2 || true
|
||
echo "请先停掉占用进程,或用 ${name}_PORT=其他端口 ./scripts/start.sh 换端口。" >&2
|
||
exit 1
|
||
fi
|
||
}
|
||
require_free_port "$BACKEND_PORT" BACKEND
|
||
require_free_port "$FRONTEND_PORT" FRONTEND
|
||
|
||
if [[ ! -d "$ROOT_DIR/frontend/node_modules" ]]; then
|
||
echo "[start] 安装前端依赖…"
|
||
(cd "$ROOT_DIR/frontend" && npm install)
|
||
fi
|
||
|
||
BACKEND_PID=""
|
||
cleanup() {
|
||
if [[ -n "$BACKEND_PID" ]]; then
|
||
kill "$BACKEND_PID" 2>/dev/null || true
|
||
fi
|
||
}
|
||
trap cleanup EXIT INT TERM
|
||
|
||
echo "[start] 后端:http://localhost:${BACKEND_PORT}/api/health"
|
||
(cd "$ROOT_DIR/backend" && exec .venv/bin/uvicorn main:app \
|
||
--host 0.0.0.0 --port "${BACKEND_PORT}" --reload) &
|
||
BACKEND_PID=$!
|
||
|
||
echo "[start] 前端:http://localhost:${FRONTEND_PORT}"
|
||
(cd "$ROOT_DIR/frontend" && exec npm run dev -- \
|
||
--host 0.0.0.0 --port "${FRONTEND_PORT}")
|