feat: 支持一键发布服务端

This commit is contained in:
richarjiang
2026-04-04 15:39:26 +08:00
parent 2b3b636c54
commit 982e569fa3
45 changed files with 852 additions and 34 deletions

212
deploy-server.sh Executable file
View File

@@ -0,0 +1,212 @@
#!/bin/bash
# ============================================================
# mp-pilates 服务端一键部署脚本
# 流程:本地构建 shared + server → 上传 → 服务器安装依赖 → PM2 重启
# ============================================================
# 部署配置
SERVER_USER="root"
SERVER_HOST="129.204.155.94"
SERVER_PATH="/usr/local/web/mp-pilates-server"
PM2_APP_NAME="mp-pilates-server"
PORT=3008
# 项目根目录(脚本所在位置)
PROJECT_ROOT="$(cd "$(dirname "$0")" && pwd)"
# 颜色输出
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'
echo_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
echo_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
echo_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# 检查 SSH 连接
echo_info "检查服务器连接..."
if ! ssh -o ConnectTimeout=5 ${SERVER_USER}@${SERVER_HOST} "echo '连接成功'" > /dev/null 2>&1; then
echo_error "无法连接到服务器 ${SERVER_HOST}"
echo_warn "请确保:"
echo_warn " 1. 服务器地址正确"
echo_warn " 2. 已配置 SSH 密钥认证或密码"
exit 1
fi
cd "${PROJECT_ROOT}"
# 1. 构建 shared 包server 依赖 shared
echo_info "构建 shared 包..."
pnpm build:shared
if [ $? -ne 0 ]; then
echo_error "shared 构建失败,部署终止"
exit 1
fi
echo_info "shared 构建完成"
# 2. 构建 server 包
echo_info "构建 server 包..."
pnpm build:server
if [ $? -ne 0 ]; then
echo_error "server 构建失败,部署终止"
exit 1
fi
echo_info "server 构建完成"
# 3. 生成 Prisma Client
echo_info "生成 Prisma Client..."
cd packages/server && pnpm prisma:generate && cd "${PROJECT_ROOT}"
if [ $? -ne 0 ]; then
echo_error "Prisma Client 生成失败"
exit 1
fi
echo_info "Prisma Client 生成完成"
# 4. 创建服务器目录
echo_info "准备服务器目录..."
ssh ${SERVER_USER}@${SERVER_HOST} "mkdir -p ${SERVER_PATH}"
# 5. 上传文件到服务器
echo_info "上传文件到服务器 ${SERVER_HOST}:${SERVER_PATH}"
# 上传 server 包含构建产物、prisma、package.json
# 注意:排除 .env 避免覆盖服务器环境配置
rsync -avz --delete \
--exclude 'node_modules' \
--exclude '.git' \
--exclude '.claude' \
--exclude '.env' \
--exclude '.env.local' \
--exclude '.DS_Store' \
--exclude '*.log' \
--exclude 'src' \
--exclude '__tests__' \
--exclude 'test' \
--exclude 'coverage' \
--exclude 'tsconfig*.json' \
--exclude 'nest-cli.json' \
packages/server/ ${SERVER_USER}@${SERVER_HOST}:${SERVER_PATH}/
if [ $? -ne 0 ]; then
echo_error "server 文件上传失败"
exit 1
fi
# 上传 shared 包构建产物
ssh ${SERVER_USER}@${SERVER_HOST} "mkdir -p ${SERVER_PATH}/../mp-pilates-shared"
rsync -avz --delete \
--exclude 'node_modules' \
--exclude 'src' \
--exclude '.DS_Store' \
packages/shared/ ${SERVER_USER}@${SERVER_HOST}:${SERVER_PATH}/../mp-pilates-shared/
if [ $? -ne 0 ]; then
echo_error "shared 文件上传失败"
exit 1
fi
# 上传本地 Prisma Client已生成好的避免服务器上版本不一致
echo_info "上传 Prisma Client..."
PRISMA_CLIENT_PATH="$(cd packages/server && node -e "console.log(require.resolve('@prisma/client/../../'))" 2>/dev/null)"
PRISMA_ENGINE_PATH="$(cd packages/server && node -e "console.log(require.resolve('@prisma/engines/../../'))" 2>/dev/null)"
echo_info "文件上传完成"
# 6. 服务器端安装依赖并重启
echo_info "服务器部署操作..."
ssh ${SERVER_USER}@${SERVER_HOST} "bash -l" << 'ENDSSH'
export PATH="$HOME/.nvm/versions/node/v22.17.1/bin:$PATH"
SERVER_PATH="/usr/local/web/mp-pilates-server"
PM2_APP_NAME="mp-pilates-server"
PORT=3008
cd ${SERVER_PATH}
# 检查 .env 是否存在
if [ ! -f .env ]; then
echo "⚠ 未找到 .env 文件,请先创建 ${SERVER_PATH}/.env"
echo " 需要配置: DATABASE_URL, JWT_SECRET, WX_APPID, WX_SECRET 等"
exit 1
fi
# 安装 pnpm如果未安装
if ! command -v pnpm &> /dev/null; then
echo "安装 pnpm..."
npm install -g pnpm
fi
# 设置 npm 镜像
npm config set registry https://registry.npmmirror.com
# 修改 package.json将 workspace:* 替换为实际路径(绕过 workspace 限制)
echo "处理依赖..."
sed -i 's|"@mp-pilates/shared": "workspace:\*"|"@mp-pilates/shared": "file:../mp-pilates-shared"|g' package.json
# 安装生产依赖
echo "安装依赖..."
pnpm install --prod --no-frozen-lockfile
# 确保 shared 包链接正确
echo "链接 shared 包..."
mkdir -p node_modules/@mp-pilates
rm -rf node_modules/@mp-pilates/shared
ln -sf ${SERVER_PATH}/../mp-pilates-shared node_modules/@mp-pilates/shared
# 使用项目本地的 prisma非全局 npx避免版本不一致
echo "生成 Prisma Client..."
./node_modules/.bin/prisma generate 2>/dev/null || npx prisma@5 generate
# 运行数据库迁移(生产环境用 deploy非交互式
echo "运行数据库迁移..."
./node_modules/.bin/prisma migrate deploy 2>/dev/null || npx prisma@5 migrate deploy
# 检查 PM2 是否安装
if ! command -v pm2 &> /dev/null; then
echo "安装 PM2..."
npm install -g pm2
fi
# 停止旧服务(如果存在)
if pm2 describe ${PM2_APP_NAME} &> /dev/null; then
echo "停止旧服务..."
pm2 stop ${PM2_APP_NAME}
pm2 delete ${PM2_APP_NAME}
fi
# 启动新服务
echo "启动服务(端口 ${PORT}..."
PORT=${PORT} pm2 start dist/main.js \
--name ${PM2_APP_NAME} \
--max-memory-restart 512M \
--log-date-format "YYYY-MM-DD HH:mm:ss"
# 保存 PM2 配置
pm2 save --force
# 等待服务启动并检查状态
sleep 3
echo "服务状态:"
pm2 status ${PM2_APP_NAME}
# 检查服务是否在线
if pm2 describe ${PM2_APP_NAME} | grep -q "online"; then
echo "✓ 服务启动成功!"
else
echo "✗ 服务启动失败,查看日志:"
pm2 logs ${PM2_APP_NAME} --lines 30 --nostream
exit 1
fi
ENDSSH
if [ $? -eq 0 ]; then
echo_info "=============================="
echo_info "部署成功!"
echo_info "应用地址: http://${SERVER_HOST}:${PORT}"
echo_info "API 地址: http://${SERVER_HOST}:${PORT}/api"
echo_info "=============================="
else
echo_error "部署失败"
exit 1
fi