#!/usr/bin/env bash # ============================================================================= # stop-frontend.sh — 停止前端开发服务器 # # 用法: # ./stop-frontend.sh # 停止全部前端服务 # ./stop-frontend.sh # 只停止指定项目 # # 可用项目: pc, meetingh5, h5, cms, build-cms, build-down # ============================================================================= set -euo pipefail source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common.sh" init_dirs init_script_log # ← 脚本执行日志 FE_PROJECTS=(pc meetingh5 h5 cms build-cms build-down) TARGET="${1:-all}" declare -A FE_PORT_NUM=( [pc]="5173" [meetingh5]="5188" [h5]="3003" [cms]="8001" [build-cms]="8002" [build-down]="8003" ) _stop_fe() { local name="$1" local pidfile="$PID_DIR/fe-${name}.pid" if [[ -f "$pidfile" ]]; then local pid; pid=$(cat "$pidfile") if kill -0 "$pid" 2>/dev/null; then # 只杀该前端的进程树,避免同一脚本启动的其它前端共享进程组时被误杀。 _kill_tree "$pid" TERM sleep 1 if kill -0 "$pid" 2>/dev/null; then _kill_tree "$pid" KILL fi success "$name 已停止 (PID=$pid)" else warn "$name 进程不存在(可能已退出)" fi rm -f "$pidfile" else warn "$name 没有 PID 记录(未运行)" fi _stop_fe_port "$name" } _kill_tree() { local pid="$1" signal="${2:-TERM}" local children child children=$(pgrep -P "$pid" 2>/dev/null || true) for child in $children; do _kill_tree "$child" "$signal" done kill "-$signal" "$pid" 2>/dev/null || true } _stop_fe_port() { local name="$1" local port="${FE_PORT_NUM[$name]}" local pids pid pids="$(lsof -tiTCP:"$port" -sTCP:LISTEN 2>/dev/null || true)" if [[ -z "$pids" ]]; then return 0 fi warn "$name 端口 $port 仍被占用,按端口清理监听进程: $pids" for pid in $pids; do _kill_tree "$pid" TERM done sleep 1 for pid in $pids; do if kill -0 "$pid" 2>/dev/null; then _kill_tree "$pid" KILL fi done pids="$(lsof -tiTCP:"$port" -sTCP:LISTEN 2>/dev/null || true)" if [[ -n "$pids" ]]; then error "$name 端口 $port 清理失败,仍被占用: $pids" return 1 fi success "$name 端口 $port 已释放" } if [[ "$TARGET" == "all" ]]; then step "停止全部前端开发服务器" for proj in "${FE_PROJECTS[@]}"; do _stop_fe "$proj" done success "所有前端服务已停止" else local_valid=false for p in "${FE_PROJECTS[@]}"; do [[ "$p" == "$TARGET" ]] && local_valid=true && break done if ! $local_valid; then error "未知项目: $TARGET" echo "可用: ${FE_PROJECTS[*]}" exit 1 fi step "停止: $TARGET" _stop_fe "$TARGET" fi