This commit is contained in:
wjsjwr 2025-11-09 19:37:39 +08:00
parent c3e965b535
commit da843ed1c4

191
start-dev.sh Normal file
View File

@ -0,0 +1,191 @@
#!/usr/bin/env bash
set -Eeuo pipefail
echo -e "\033[32m正在启动 Digital Embryo 开发环境...\033[0m"
# 获取当前脚本所在目录
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
# 前后端目录
FRONTEND_DIR="${SCRIPT_DIR}/embryo-frontend"
BACKEND_DIR="${SCRIPT_DIR}/embryo-backend"
# 颜色输出
yellow() { echo -e "\033[33m$*\033[0m"; }
green() { echo -e "\033[32m$*\033[0m"; }
cyan() { echo -e "\033[36m$*\033[0m"; }
red() { echo -e "\033[31m$*\033[0m"; }
# PATH 修正助手
prepend_path_if_dir_exists() {
local dir="$1"
if [[ -d "$dir" ]] && [[ ":$PATH:" != *":${dir}:"* ]]; then
export PATH="${dir}:${PATH}"
fi
}
# 确保 brew 可用(不强制安装,避免交互)
has_brew() { command -v brew >/dev/null 2>&1; }
# 安装 npm优先 brew其次 nvm
ensure_npm() {
if command -v npm >/dev/null 2>&1; then
return 0
fi
yellow "未检测到 npm尝试自动安装..."
if has_brew; then
yellow "使用 Homebrew 安装 Node.js包含 npm..."
if brew install node; then
green "已通过 Homebrew 安装 Node.js/npm"
return 0
else
red "通过 Homebrew 安装 Node.js 失败,回退到 nvm 安装方式"
fi
fi
# 回退:安装 nvm 并安装 Node LTS
yellow "安装 nvm..."
export NVM_DIR="$HOME/.nvm"
mkdir -p "$NVM_DIR"
if curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash; then
# 当前会话加载 nvm
if [[ -s "$NVM_DIR/nvm.sh" ]]; then
# shellcheck disable=SC1090
. "$NVM_DIR/nvm.sh"
fi
if [[ -s "$NVM_DIR/bash_completion" ]]; then
# shellcheck disable=SC1090
. "$NVM_DIR/bash_completion"
fi
yellow "使用 nvm 安装 Node.js LTS..."
nvm install --lts
nvm use --lts
nvm alias default 'lts/*' || true
else
red "安装 nvm 失败"
fi
if ! command -v npm >/dev/null 2>&1; then
red "自动安装 npm 失败,请手动安装 Node.js/npm 后重试。"
exit 1
fi
green "npm 安装完成"
}
# 安装 uv优先 brew其次官方脚本
ensure_uv() {
if command -v uv >/dev/null 2>&1; then
return 0
fi
yellow "未检测到 uv尝试自动安装..."
if has_brew; then
yellow "使用 Homebrew 安装 uv..."
if brew install uv; then
green "已通过 Homebrew 安装 uv"
return 0
else
red "通过 Homebrew 安装 uv 失败,回退到官方安装脚本"
fi
fi
# 回退:官方安装脚本(将二进制置于 ~/.local/bin 或 ~/.cargo/bin
if curl -fsSL https://astral.sh/uv/install.sh | sh; then
# 尝试将常见安装目录加入 PATH仅当前会话
prepend_path_if_dir_exists "$HOME/.local/bin"
prepend_path_if_dir_exists "$HOME/.cargo/bin"
else
red "运行 uv 官方安装脚本失败"
fi
if ! command -v uv >/dev/null 2>&1; then
red "自动安装 uv 失败,请手动安装 uv 后重试(可用 brew install uv。"
exit 1
fi
green "uv 安装完成"
}
# 基础校验
if [[ ! -d "${FRONTEND_DIR}" ]]; then
echo "前端目录不存在: ${FRONTEND_DIR}" >&2
exit 1
fi
if [[ ! -d "${BACKEND_DIR}" ]]; then
echo "后端目录不存在: ${BACKEND_DIR}" >&2
exit 1
fi
PACKAGE_JSON_PATH="${FRONTEND_DIR}/package.json"
APP_PY_PATH="${BACKEND_DIR}/app.py"
if [[ ! -f "${PACKAGE_JSON_PATH}" ]]; then
echo "package.json 文件不存在: ${PACKAGE_JSON_PATH}" >&2
exit 1
fi
if [[ ! -f "${APP_PY_PATH}" ]]; then
echo "app.py 文件不存在: ${APP_PY_PATH}" >&2
exit 1
fi
# 依赖校验与自动安装
ensure_npm
ensure_uv
echo -e "\033[33m启动前端开发服务器...\033[0m"
pushd "${FRONTEND_DIR}" >/dev/null
npm run dev &
FRONTEND_PID=$!
popd >/dev/null
echo -e "\033[33m启动后端API服务器...\033[0m"
pushd "${SCRIPT_DIR}" >/dev/null
uv run "${BACKEND_DIR}/app.py" &
BACKEND_PID=$!
popd >/dev/null
echo -e "\033[32m两个服务都已启动!\033[0m"
echo -e "\033[36m前端开发服务器通常运行在: http://localhost:5173\033[0m"
echo -e "\033[36m后端API服务器通常运行在: http://localhost:5000\033[0m"
echo
echo -e "\033[31m按 Ctrl+C 停止所有服务\033[0m"
cleanup() {
echo -e "\033[33m正在停止所有服务...\033[0m"
if ps -p ${FRONTEND_PID} >/dev/null 2>&1; then
kill ${FRONTEND_PID} 2>/dev/null || true
wait ${FRONTEND_PID} 2>/dev/null || true
fi
if ps -p ${BACKEND_PID} >/dev/null 2>&1; then
kill ${BACKEND_PID} 2>/dev/null || true
wait ${BACKEND_PID} 2>/dev/null || true
fi
echo -e "\033[32m所有服务已停止\033[0m"
}
trap cleanup INT TERM
# 监控:若任一服务退出则结束脚本并清理
while true; do
if ! ps -p ${FRONTEND_PID} >/dev/null 2>&1; then
echo "前端服务已退出"
break
fi
if ! ps -p ${BACKEND_PID} >/dev/null 2>&1; then
echo "后端服务已退出"
break
fi
sleep 1
done
cleanup
exit 0