sync
This commit is contained in:
parent
c3e965b535
commit
da843ed1c4
191
start-dev.sh
Normal file
191
start-dev.sh
Normal 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
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user