feat: 添加前后端一体化 Docker 部署支持

- 创建根目录 Dockerfile,支持前后端一起部署到一个容器
- 添加 Nginx 配置,自动代理后端 API 和 WebSocket
- 创建启动脚本,同时启动后端和 Nginx
- 更新 docker-compose.yml 支持一体化部署
- 创建一体化部署脚本 deploy.sh
- 修复前端环境变量支持,默认使用相对路径
- 优化部署脚本:.env 文件不存在时创建后终止部署
- 更新部署文档,添加一体化部署说明
This commit is contained in:
WrBug
2025-12-03 03:08:53 +08:00
parent 59722d7311
commit 1216fc5ed5
13 changed files with 615 additions and 65 deletions
+83 -43
View File
@@ -1,7 +1,8 @@
#!/bin/bash
# PolyHermes 前端构建脚本
# 支持自定义后端 API 地址
# 支持通过环境变量配置后端 URL(用于跨域场景)
# 默认使用相对路径,通过反向代理转发到后端
set -e
@@ -11,10 +12,6 @@ GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 默认配置
DEFAULT_API_URL="http://127.0.0.1:8000"
API_URL="${VITE_API_URL:-$DEFAULT_API_URL}"
# 打印信息
info() {
echo -e "${GREEN}[INFO]${NC} $1"
@@ -44,40 +41,70 @@ check_node() {
info "Node.js 环境检查通过: $(node -v)"
}
# 创建环境配置文件
# 创建环境配置文件(可选)
create_env_file() {
info "创建环境配置文件..."
# 解析 API URL,提取协议、主机和端口
if [[ $API_URL == http* ]]; then
# 提取协议和主机
PROTOCOL=$(echo $API_URL | sed -E 's|^([^:]+)://.*|\1|')
HOST_PORT=$(echo $API_URL | sed -E 's|^[^:]+://([^/]+).*|\1|')
HOST=$(echo $HOST_PORT | cut -d':' -f1)
PORT=$(echo $HOST_PORT | cut -d':' -f2)
# 如果设置了环境变量,创建 .env.production 文件
if [ -n "$VITE_API_URL" ] || [ -n "$VITE_WS_URL" ]; then
info "检测到环境变量,创建 .env.production 文件..."
# 构建 WebSocket URL
if [ "$PROTOCOL" = "https" ]; then
WS_PROTOCOL="wss"
# 解析 API URL,提取协议、主机和端口
if [ -n "$VITE_API_URL" ]; then
API_URL="$VITE_API_URL"
if [[ $API_URL == http* ]]; then
PROTOCOL=$(echo $API_URL | sed -E 's|^([^:]+)://.*|\1|')
if [ "$PROTOCOL" = "https" ]; then
WS_PROTOCOL="wss"
else
WS_PROTOCOL="ws"
fi
HOST_PORT=$(echo $API_URL | sed -E 's|^[^:]+://([^/]+).*|\1|')
WS_URL="${WS_PROTOCOL}://${HOST_PORT}"
else
error "VITE_API_URL 格式错误,应为 http://host:port 或 https://host:port"
exit 1
fi
else
WS_PROTOCOL="ws"
# 如果只设置了 WS_URL,从 WS_URL 推导 API_URL
if [ -n "$VITE_WS_URL" ]; then
WS_URL="$VITE_WS_URL"
if [[ $WS_URL == ws* ]]; then
WS_PROTOCOL=$(echo $WS_URL | sed -E 's|^([^:]+)://.*|\1|')
if [ "$WS_PROTOCOL" = "wss" ]; then
API_PROTOCOL="https"
else
API_PROTOCOL="http"
fi
HOST_PORT=$(echo $WS_URL | sed -E 's|^[^:]+://([^/]+).*|\1|')
API_URL="${API_PROTOCOL}://${HOST_PORT}"
else
error "VITE_WS_URL 格式错误,应为 ws://host:port 或 wss://host:port"
exit 1
fi
fi
fi
WS_URL="${WS_PROTOCOL}://${HOST}:${PORT}"
else
error "API URL 格式错误,应为 http://host:port 或 https://host:port"
exit 1
fi
# 创建 .env.production 文件
cat > .env.production <<EOF
# 后端 API 地址
VITE_API_URL=$API_URL
VITE_WS_URL=$WS_URL
# 如果同时设置了两个环境变量,使用设置的值
if [ -n "$VITE_WS_URL" ]; then
WS_URL="$VITE_WS_URL"
fi
cat > .env.production <<EOF
# 后端 API 地址(可选,用于跨域场景)
# 如果未设置,前端将使用相对路径 /api(通过反向代理转发)
VITE_API_URL=${VITE_API_URL:-}
VITE_WS_URL=${VITE_WS_URL:-${WS_URL:-}}
EOF
info "环境配置已创建: .env.production"
info " API URL: $API_URL"
info " WebSocket URL: $WS_URL"
info "环境配置已创建: .env.production"
if [ -n "$VITE_API_URL" ]; then
info " API URL: $VITE_API_URL"
fi
if [ -n "$VITE_WS_URL" ] || [ -n "$WS_URL" ]; then
info " WebSocket URL: ${VITE_WS_URL:-$WS_URL}"
fi
else
info "未设置环境变量,前端将使用相对路径(通过反向代理转发)"
fi
}
# 构建应用
@@ -114,23 +141,36 @@ main() {
# 解析参数
if [ "$1" = "--api-url" ] && [ -n "$2" ]; then
API_URL="$2"
info "使用自定义 API 地址: $API_URL"
elif [ -n "$VITE_API_URL" ]; then
info "使用环境变量 API 地址: $API_URL"
else
info "使用默认 API 地址: $API_URL"
warn "提示: 可通过环境变量 VITE_API_URL 或参数 --api-url 自定义后端地址"
export VITE_API_URL="$2"
info "使用自定义 API 地址: $VITE_API_URL"
elif [ "$1" = "--ws-url" ] && [ -n "$2" ]; then
export VITE_WS_URL="$2"
info "使用自定义 WebSocket 地址: $VITE_WS_URL"
fi
create_env_file
if [ -z "$VITE_API_URL" ] && [ -z "$VITE_WS_URL" ]; then
info "前端将使用相对路径 /api 和 /ws"
info "请确保在生产环境配置反向代理(Nginx/Apache"
fi
build_app
echo ""
info "构建完成!"
info "部署方式:"
info " 1. 静态文件服务器:将 dist/ 目录部署到 Nginx、Apache 等"
info " 2. 使用 serve 预览:npx serve -s dist -l 3000"
if [ -n "$VITE_API_URL" ] || [ -n "$VITE_WS_URL" ]; then
info " 已配置后端地址,前端将直接请求后端服务器"
else
info " 1. 静态文件服务器:将 dist/ 目录部署到 Nginx、Apache 等"
info " 2. 配置反向代理:/api -> 后端地址,/ws -> 后端 WebSocket 地址"
fi
info " 3. 使用 serve 预览:npx serve -s dist -l 3000"
echo ""
info "提示:可通过环境变量配置后端地址:"
info " VITE_API_URL=http://your-backend.com:8000 ./build.sh"
info " 或使用参数:./build.sh --api-url http://your-backend.com:8000"
}
main "$@"
+4 -5
View File
@@ -5,17 +5,16 @@ import { wsManager } from './websocket'
/**
* API 基础配置
* 支持通过环境变量 VITE_API_URL 配置后端地址
* 默认使用相对路径 /api(适用于同域部署
* 如果设置了 VITE_API_URL,则使用完整 URL
* 默认使用相对路径 /api(通过反向代理转发)
* 如果设置了 VITE_API_URL 环境变量,则使用完整 URL(用于跨域场景
*/
const getBaseURL = (): string => {
const envApiUrl = import.meta.env.VITE_API_URL
if (envApiUrl) {
// 如果设置了环境变量,使用完整 URL
// 如果设置了环境变量,使用完整 URL(支持跨域)
return `${envApiUrl}/api`
}
// 否则使用相对路径(适用于开发环境代理或同域部署
// 否则使用相对路径(通过反向代理转发
return '/api'
}
+4 -3
View File
@@ -325,17 +325,18 @@ class WebSocketManager {
/**
* 获取 WebSocket URL(带token认证)
* 支持通过环境变量 VITE_WS_URL 配置 WebSocket 地址
* 默认使用相对路径 /ws(通过反向代理转发)
* 如果设置了 VITE_WS_URL 环境变量,则使用完整 URL(用于跨域场景)
*/
private getWebSocketUrl(): string {
const envWsUrl = import.meta.env.VITE_WS_URL
let wsBaseUrl: string
if (envWsUrl) {
// 如果设置了环境变量,使用完整 URL
// 如果设置了环境变量,使用完整 URL(支持跨域)
wsBaseUrl = envWsUrl
} else {
// 否则使用相对路径(适用于开发环境代理或同域部署
// 否则使用相对路径(通过反向代理转发
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
const host = window.location.host
wsBaseUrl = `${protocol}//${host}`
+3 -8
View File
@@ -6,7 +6,8 @@ export default defineConfig(({ mode }) => {
// 加载环境变量
const env = loadEnv(mode, process.cwd(), '')
// 从环境变量获取 API 地址,默认使用 localhost:8000
// 从环境变量获取后端地址,用于开发环境代理
// 如果未设置,使用默认值 localhost:8000
const API_URL = env.VITE_API_URL || 'http://localhost:8000'
const WS_URL = env.VITE_WS_URL || 'ws://localhost:8000'
@@ -17,8 +18,7 @@ export default defineConfig(({ mode }) => {
proxy: {
'/api': {
target: API_URL,
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '/api')
changeOrigin: true
},
'/ws': {
target: WS_URL,
@@ -26,11 +26,6 @@ export default defineConfig(({ mode }) => {
changeOrigin: true
}
}
},
// 定义环境变量,在构建时注入
define: {
'import.meta.env.VITE_API_URL': JSON.stringify(API_URL),
'import.meta.env.VITE_WS_URL': JSON.stringify(WS_URL)
}
}
})