feat: 添加完整的部署支持

- 后端多环境配置(dev, prod)
- Docker 部署支持(Dockerfile, docker-compose.yml)
- Java 部署脚本(deploy.sh)
- 前端构建脚本(build.sh,支持自定义后端地址)
- 健康检查接口(/api/health)
- 完整的部署文档(docs/DEPLOYMENT.md)
- 前端环境变量支持(VITE_API_URL, VITE_WS_URL)
This commit is contained in:
WrBug
2025-12-03 02:48:02 +08:00
parent 220afd748f
commit 59722d7311
14 changed files with 1047 additions and 47 deletions
+37 -26
View File
@@ -80,9 +80,9 @@ polymarket-bot/
- JDK 17+
- Node.js 18+
- MySQL 8.0+
- Gradle 7.5+
- Gradle 7.5+(或使用 Gradle Wrapper
### 安装步骤
### 开发环境
1. **克隆仓库**
@@ -99,33 +99,16 @@ cd PolyHermes
CREATE DATABASE polymarket_bot CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
```
3. **配置后端**
编辑 `backend/src/main/resources/application.properties`
```properties
# 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/polymarket_bot?useSSL=false&serverTimezone=UTC&characterEncoding=utf8mb4
spring.datasource.username=${DB_USERNAME:root}
spring.datasource.password=${DB_PASSWORD:your_password}
# 服务器端口
server.port=${SERVER_PORT:8000}
# Polygon RPC(用于查询链上余额)
polygon.rpc.url=${POLYGON_RPC_URL:https://polygon-rpc.com}
```
4. **启动后端**
3. **启动后端**
```bash
cd backend
./gradlew bootRun
```
后端服务将在 `http://localhost:8000` 启动。
后端服务将在 `http://localhost:8000` 启动(开发环境)
5. **启动前端**
4. **启动前端**
```bash
cd frontend
@@ -135,6 +118,34 @@ npm run dev
前端应用将在 `http://localhost:3000` 启动。
### 生产部署
详细的部署文档请参考:[部署文档](docs/DEPLOYMENT.md)
#### 快速部署
**后端(Java 方式)**:
```bash
cd backend
./deploy.sh java
```
**后端(Docker 方式)**:
```bash
cd backend
./deploy.sh docker
```
**前端**:
```bash
cd frontend
# 使用默认后端地址
./build.sh
# 或指定自定义后端地址
./build.sh --api-url http://your-backend-server.com:8000
```
## 📖 使用指南
### 账户管理
@@ -180,11 +191,11 @@ npm run dev
3. 启用代理并测试连接
4. 配置实时生效,无需重启服务
## 📚 API 文档
## 📚 文档
详细的 API 文档请参考:
- [跟单系统需求文档](docs/copy-trading-requirements.md)
- [前端需求文档](docs/copy-trading-frontend-requirements.md)
- [部署文档](docs/DEPLOYMENT.md) - 详细的部署指南(Java/Docker
- [跟单系统需求文档](docs/copy-trading-requirements.md) - 后端 API 接口文档
- [前端需求文档](docs/copy-trading-frontend-requirements.md) - 前端功能文档
## 🤝 贡献
+33
View File
@@ -0,0 +1,33 @@
# Gradle
.gradle/
build/
out/
bin/
*.log
# IDE
.idea/
*.iml
*.iws
*.ipr
.vscode/
*.swp
*.swo
*~
.DS_Store
# 部署相关
deploy/
*.jar
!build/libs/*.jar
# 环境配置
.env
.env.local
.env.*.local
# 其他
*.bak
*.backup
*.old
+48
View File
@@ -0,0 +1,48 @@
# 多阶段构建 Dockerfile
# 阶段1:构建应用
FROM gradle:8.5-jdk17 AS build
WORKDIR /app
# 复制 Gradle 配置文件
COPY build.gradle.kts settings.gradle.kts ./
COPY gradle ./gradle
# 下载依赖(利用 Docker 缓存)
RUN gradle dependencies --no-daemon || true
# 复制源代码
COPY src ./src
# 构建应用
RUN gradle bootJar --no-daemon
# 阶段2:运行应用
FROM openjdk:17-jre-slim
WORKDIR /app
# 安装必要的工具
RUN apt-get update && \
apt-get install -y curl && \
rm -rf /var/lib/apt/lists/*
# 从构建阶段复制 JAR 文件
COPY --from=build /app/build/libs/*.jar app.jar
# 创建非 root 用户
RUN useradd -m -u 1000 appuser && \
chown -R appuser:appuser /app
USER appuser
# 暴露端口
EXPOSE 8000
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
CMD curl -f http://localhost:8000/api/health || exit 1
# 启动应用
ENTRYPOINT ["java", "-jar", "app.jar"]
+203
View File
@@ -0,0 +1,203 @@
#!/bin/bash
# PolyHermes 后端部署脚本
# 支持 Java 直接部署和 Docker 部署
set -e
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 配置
APP_NAME="polymarket-bot-backend"
JAR_NAME="polymarket-bot-backend-1.0.0.jar"
DEPLOY_DIR="./deploy"
PROFILE="${SPRING_PROFILES_ACTIVE:-prod}"
# 打印信息
info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查 Java 环境
check_java() {
if ! command -v java &> /dev/null; then
error "Java 未安装,请先安装 Java 17+"
exit 1
fi
JAVA_VERSION=$(java -version 2>&1 | awk -F '"' '/version/ {print $2}' | cut -d'.' -f1)
if [ "$JAVA_VERSION" -lt 17 ]; then
error "Java 版本过低,需要 Java 17+,当前版本: $JAVA_VERSION"
exit 1
fi
info "Java 环境检查通过: $(java -version 2>&1 | head -n 1)"
}
# 构建应用
build_app() {
info "开始构建应用..."
if ! command -v gradle &> /dev/null; then
error "Gradle 未安装,请先安装 Gradle 或使用 Gradle Wrapper"
exit 1
fi
./gradlew clean bootJar
if [ ! -f "build/libs/$JAR_NAME" ]; then
error "构建失败,JAR 文件不存在"
exit 1
fi
info "构建完成: build/libs/$JAR_NAME"
}
# Java 部署
deploy_java() {
info "使用 Java 方式部署..."
# 创建部署目录
mkdir -p "$DEPLOY_DIR"
# 复制 JAR 文件
cp "build/libs/$JAR_NAME" "$DEPLOY_DIR/"
# 创建启动脚本
cat > "$DEPLOY_DIR/start.sh" <<EOF
#!/bin/bash
cd \$(dirname \$0)
# 设置 JVM 参数
JVM_OPTS="-Xms512m -Xmx1024m -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
# 启动应用
java \$JVM_OPTS -jar $JAR_NAME --spring.profiles.active=$PROFILE
EOF
chmod +x "$DEPLOY_DIR/start.sh"
# 创建 systemd 服务文件(可选)
cat > "$DEPLOY_DIR/${APP_NAME}.service" <<EOF
[Unit]
Description=PolyHermes Backend Service
After=network.target mysql.service
[Service]
Type=simple
User=\${USER}
WorkingDirectory=$DEPLOY_DIR
ExecStart=/usr/bin/java -Xms512m -Xmx1024m -XX:+UseG1GC -jar $JAR_NAME --spring.profiles.active=$PROFILE
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
info "Java 部署文件已创建在: $DEPLOY_DIR"
info "启动方式: cd $DEPLOY_DIR && ./start.sh"
info "或使用 systemd: sudo cp ${APP_NAME}.service /etc/systemd/system/ && sudo systemctl start ${APP_NAME}"
}
# Docker 部署
deploy_docker() {
info "使用 Docker 方式部署..."
if ! command -v docker &> /dev/null; then
error "Docker 未安装,请先安装 Docker"
exit 1
fi
if ! command -v docker-compose &> /dev/null; then
error "Docker Compose 未安装,请先安装 Docker Compose"
exit 1
fi
# 创建 .env 文件(如果不存在)
if [ ! -f ".env" ]; then
warn ".env 文件不存在,创建示例文件..."
cat > .env <<EOF
# 数据库配置
DB_URL=jdbc:mysql://mysql:3306/polymarket_bot?useSSL=false&serverTimezone=UTC&characterEncoding=utf8mb4
DB_USERNAME=root
DB_PASSWORD=your_password_here
# Spring Profile
SPRING_PROFILES_ACTIVE=prod
# 服务器端口
SERVER_PORT=8000
# Polygon RPC
POLYGON_RPC_URL=https://polygon-rpc.com
# JWT 密钥(生产环境必须修改)
JWT_SECRET=your-jwt-secret-key-change-in-production
# 管理员密码重置密钥(生产环境必须修改)
ADMIN_RESET_PASSWORD_KEY=your-admin-reset-key-change-in-production
EOF
warn "请编辑 .env 文件配置相关参数"
fi
# 构建并启动
info "构建 Docker 镜像..."
docker-compose build
info "启动服务..."
docker-compose up -d
info "Docker 部署完成"
info "查看日志: docker-compose logs -f"
info "停止服务: docker-compose down"
}
# 主函数
main() {
echo "=========================================="
echo " PolyHermes 后端部署脚本"
echo "=========================================="
echo ""
# 解析参数
DEPLOY_MODE="${1:-java}"
case "$DEPLOY_MODE" in
java)
check_java
build_app
deploy_java
;;
docker)
deploy_docker
;;
build)
check_java
build_app
;;
*)
echo "用法: $0 [java|docker|build]"
echo ""
echo " java - Java 直接部署(默认)"
echo " docker - Docker 部署"
echo " build - 仅构建应用"
exit 1
;;
esac
}
main "$@"
+54
View File
@@ -0,0 +1,54 @@
version: '3.8'
services:
backend:
build:
context: .
dockerfile: Dockerfile
container_name: polymarket-bot-backend
ports:
- "${SERVER_PORT:-8000}:8000"
environment:
- SPRING_PROFILES_ACTIVE=${SPRING_PROFILES_ACTIVE:-prod}
- DB_URL=${DB_URL:-jdbc:mysql://mysql:3306/polymarket_bot?useSSL=false&serverTimezone=UTC&characterEncoding=utf8mb4}
- DB_USERNAME=${DB_USERNAME:-root}
- DB_PASSWORD=${DB_PASSWORD:-}
- SERVER_PORT=8000
- POLYGON_RPC_URL=${POLYGON_RPC_URL:-https://polygon-rpc.com}
- JWT_SECRET=${JWT_SECRET:-change-me-in-production}
- ADMIN_RESET_PASSWORD_KEY=${ADMIN_RESET_PASSWORD_KEY:-change-me-in-production}
depends_on:
mysql:
condition: service_healthy
restart: unless-stopped
networks:
- polymarket-network
mysql:
image: mysql:8.2
container_name: polymarket-bot-mysql
ports:
- "${MYSQL_PORT:-3306}:3306"
environment:
- MYSQL_ROOT_PASSWORD=${DB_PASSWORD:-rootpassword}
- MYSQL_DATABASE=polymarket_bot
- MYSQL_CHARACTER_SET_SERVER=utf8mb4
- MYSQL_COLLATION_SERVER=utf8mb4_unicode_ci
volumes:
- mysql-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${DB_PASSWORD:-rootpassword}"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
networks:
- polymarket-network
volumes:
mysql-data:
networks:
polymarket-network:
driver: bridge
@@ -0,0 +1,26 @@
package com.wrbug.polymarketbot.controller
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import java.util.*
/**
* 健康检查控制器
* 用于 Docker 健康检查和监控
*/
@RestController
@RequestMapping("/api/health")
class HealthController {
@GetMapping
fun health(): ResponseEntity<Map<String, Any>> {
return ResponseEntity.ok(mapOf(
"status" to "UP",
"timestamp" to System.currentTimeMillis(),
"service" to "polymarket-bot-backend"
))
}
}
@@ -1,8 +1,8 @@
# 应用配置
spring.application.name=polymarket-bot-backend
# 数据源配置
spring.datasource.url=jdbc:mysql://localhost:3306/polymarket_bot?useSSL=false&serverTimezone=UTC&characterEncoding=utf8&allowPublicKeyRetrieval=true
# 数据源配置(默认配置,可通过环境变量覆盖)
spring.datasource.url=${DB_URL:jdbc:mysql://localhost:3306/polymarket_bot?useSSL=false&serverTimezone=UTC&characterEncoding=utf8&allowPublicKeyRetrieval=true}
spring.datasource.username=${DB_USERNAME:root}
spring.datasource.password=${DB_PASSWORD:11111111}
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
@@ -25,6 +25,10 @@ spring.flyway.baseline-on-migrate=true
# 服务器配置
server.port=${SERVER_PORT:8000}
# Spring Profile 配置
# 默认使用 dev 环境,可通过 --spring.profiles.active=prod 切换
spring.profiles.active=${SPRING_PROFILES_ACTIVE:dev}
# 日志配置
logging.level.root=INFO
logging.level.com.wrbug.polymarketbot=DEBUG
+399
View File
@@ -0,0 +1,399 @@
# PolyHermes 部署文档
本文档介绍如何部署 PolyHermes 项目,包括后端和前端的不同部署方式。
## 目录
- [后端部署](#后端部署)
- [Java 直接部署](#java-直接部署)
- [Docker 部署](#docker-部署)
- [前端部署](#前端部署)
- [环境配置](#环境配置)
- [常见问题](#常见问题)
## 后端部署
### Java 直接部署
#### 前置要求
- JDK 17+
- MySQL 8.0+
- Gradle 7.5+(或使用 Gradle Wrapper
#### 部署步骤
1. **构建应用**
```bash
cd backend
./gradlew clean bootJar
```
构建产物位于 `build/libs/polymarket-bot-backend-1.0.0.jar`
2. **使用部署脚本(推荐)**
```bash
# 构建并创建部署文件
./deploy.sh java
# 或仅构建
./deploy.sh build
```
脚本会自动:
- 检查 Java 环境
- 构建应用
- 创建部署目录和启动脚本
- 生成 systemd 服务文件(可选)
3. **手动启动**
```bash
# 开发环境
java -jar build/libs/polymarket-bot-backend-1.0.0.jar --spring.profiles.active=dev
# 生产环境
java -jar build/libs/polymarket-bot-backend-1.0.0.jar --spring.profiles.active=prod
```
4. **使用 systemd 管理(Linux**
```bash
# 复制服务文件
sudo cp deploy/polymarket-bot-backend.service /etc/systemd/system/
# 编辑服务文件,修改路径和用户
sudo nano /etc/systemd/system/polymarket-bot-backend.service
# 启动服务
sudo systemctl daemon-reload
sudo systemctl enable polymarket-bot-backend
sudo systemctl start polymarket-bot-backend
# 查看日志
sudo journalctl -u polymarket-bot-backend -f
```
### Docker 部署
#### 前置要求
- Docker 20.10+
- Docker Compose 2.0+
#### 部署步骤
1. **使用部署脚本(推荐)**
```bash
cd backend
./deploy.sh docker
```
脚本会自动:
- 检查 Docker 环境
- 创建 `.env` 配置文件(如果不存在)
- 构建 Docker 镜像
- 启动服务
2. **手动部署**
```bash
# 创建 .env 文件
cat > .env <<EOF
DB_URL=jdbc:mysql://mysql:3306/polymarket_bot?useSSL=false&serverTimezone=UTC&characterEncoding=utf8mb4
DB_USERNAME=root
DB_PASSWORD=your_password_here
SPRING_PROFILES_ACTIVE=prod
SERVER_PORT=8000
POLYGON_RPC_URL=https://polygon-rpc.com
JWT_SECRET=your-jwt-secret-key-change-in-production
ADMIN_RESET_PASSWORD_KEY=your-admin-reset-key-change-in-production
EOF
# 构建并启动
docker-compose up -d
# 查看日志
docker-compose logs -f
# 停止服务
docker-compose down
```
3. **仅构建镜像**
```bash
docker build -t polymarket-bot-backend:latest .
```
4. **运行容器**
```bash
docker run -d \
--name polymarket-bot-backend \
-p 8000:8000 \
-e SPRING_PROFILES_ACTIVE=prod \
-e DB_URL=jdbc:mysql://host.docker.internal:3306/polymarket_bot?useSSL=false \
-e DB_USERNAME=root \
-e DB_PASSWORD=your_password \
-e JWT_SECRET=your-jwt-secret \
polymarket-bot-backend:latest
```
## 前端部署
### 构建步骤
1. **使用构建脚本(推荐)**
```bash
cd frontend
# 使用默认后端地址(http://127.0.0.1:8000
./build.sh
# 或指定自定义后端地址
./build.sh --api-url http://your-backend-server.com:8000
# 或使用环境变量
VITE_API_URL=http://your-backend-server.com:8000 ./build.sh
```
2. **手动构建**
```bash
cd frontend
# 创建环境配置文件
cat > .env.production <<EOF
VITE_API_URL=http://your-backend-server.com:8000
VITE_WS_URL=ws://your-backend-server.com:8000
EOF
# 安装依赖(首次)
npm install
# 构建
npm run build
```
构建产物位于 `dist/` 目录。
### 部署方式
#### 方式1Nginx 部署
```nginx
server {
listen 80;
server_name your-domain.com;
root /path/to/frontend/dist;
index index.html;
# API 代理
location /api {
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# WebSocket 代理
location /ws {
proxy_pass http://localhost:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
# 前端路由(SPA
location / {
try_files $uri $uri/ /index.html;
}
}
```
#### 方式2Apache 部署
```apache
<VirtualHost *:80>
ServerName your-domain.com
DocumentRoot /path/to/frontend/dist
# API 代理
ProxyPass /api http://localhost:8000/api
ProxyPassReverse /api http://localhost:8000/api
# WebSocket 代理
ProxyPass /ws ws://localhost:8000/ws
ProxyPassReverse /ws ws://localhost:8000/ws
# 前端路由(SPA
<Directory /path/to/frontend/dist>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</Directory>
</VirtualHost>
```
#### 方式3:使用 serve(开发/测试)
```bash
# 安装 serve
npm install -g serve
# 启动服务
serve -s dist -l 3000
```
## 环境配置
### 后端环境变量
| 变量名 | 说明 | 默认值 | 必需 |
|--------|------|--------|------|
| `SPRING_PROFILES_ACTIVE` | Spring Profile | `dev` | 否 |
| `DB_URL` | 数据库连接 URL | - | 是(生产) |
| `DB_USERNAME` | 数据库用户名 | `root` | 是(生产) |
| `DB_PASSWORD` | 数据库密码 | - | 是(生产) |
| `SERVER_PORT` | 服务器端口 | `8000` | 否 |
| `POLYGON_RPC_URL` | Polygon RPC 地址 | `https://polygon-rpc.com` | 否 |
| `JWT_SECRET` | JWT 密钥 | - | 是(生产) |
| `ADMIN_RESET_PASSWORD_KEY` | 管理员密码重置密钥 | - | 是(生产) |
### 前端环境变量
| 变量名 | 说明 | 默认值 |
|--------|------|--------|
| `VITE_API_URL` | 后端 API 地址 | `http://127.0.0.1:8000` |
| `VITE_WS_URL` | WebSocket 地址 | `ws://127.0.0.1:8000` |
### 配置文件说明
#### 后端配置文件
- `application.properties` - 基础配置(所有环境共享)
- `application-dev.properties` - 开发环境配置
- `application-prod.properties` - 生产环境配置
通过 `--spring.profiles.active=prod` 或环境变量 `SPRING_PROFILES_ACTIVE=prod` 切换环境。
#### 前端环境变量
Vite 使用 `.env.production` 文件在构建时注入环境变量。构建脚本会自动创建此文件。
## 常见问题
### 1. 数据库连接失败
**问题**: 后端无法连接数据库
**解决方案**:
- 检查数据库服务是否运行
- 检查数据库连接 URL、用户名、密码是否正确
- 检查防火墙是否允许连接
- 对于 Docker 部署,确保使用正确的数据库地址(`mysql` 而非 `localhost`
### 2. 前端无法连接后端
**问题**: 前端请求后端 API 失败
**解决方案**:
- 检查后端服务是否运行
- 检查 `VITE_API_URL` 配置是否正确
- 检查 CORS 配置(如果跨域)
- 检查网络连接和防火墙
### 3. WebSocket 连接失败
**问题**: WebSocket 无法建立连接
**解决方案**:
- 检查 `VITE_WS_URL` 配置是否正确
- 检查 WebSocket 代理配置(Nginx/Apache
- 检查防火墙是否允许 WebSocket 连接
- 检查后端 WebSocket 服务是否正常
### 4. Docker 容器无法访问数据库
**问题**: Docker 容器中的后端无法连接宿主机数据库
**解决方案**:
- 使用 `host.docker.internal` 作为数据库地址(Mac/Windows
- 使用 Docker 网络连接(推荐使用 docker-compose
- 检查数据库是否允许远程连接
### 5. 构建失败
**问题**: 前端或后端构建失败
**解决方案**:
- 检查 Node.js 版本(需要 18+
- 检查 Java 版本(需要 17+)
- 清理缓存后重新构建:
```bash
# 前端
rm -rf node_modules dist
npm install
npm run build
# 后端
./gradlew clean build
```
## 生产环境检查清单
- [ ] 修改所有默认密码和密钥(JWT_SECRET、ADMIN_RESET_PASSWORD_KEY、数据库密码)
- [ ] 配置正确的数据库连接(使用 SSL)
- [ ] 设置正确的 Spring Profile`prod`
- [ ] 配置正确的后端 API 地址(前端)
- [ ] 配置反向代理(Nginx/Apache
- [ ] 配置 HTTPS(生产环境推荐)
- [ ] 配置防火墙规则
- [ ] 设置日志轮转
- [ ] 配置监控和告警
- [ ] 定期备份数据库
## 性能优化建议
### 后端
- 调整 JVM 参数(堆内存、GC 策略)
- 配置数据库连接池大小
- 启用 HTTP 压缩
- 配置缓存策略
### 前端
- 启用 Gzip 压缩(Nginx
- 配置静态资源缓存
- 使用 CDN 加速
- 启用 HTTP/2
## 安全建议
- 使用 HTTPS(生产环境必须)
- 配置 CORS 白名单
- 定期更新依赖包
- 使用强密码和密钥
- 限制数据库访问权限
- 配置防火墙规则
- 定期备份数据
- 监控异常访问
## 技术支持
如有问题,请提交 Issue 到 [GitHub](https://github.com/WrBug/PolyHermes) 或联系 [Twitter](https://x.com/quant_tr)。
+34
View File
@@ -0,0 +1,34 @@
# 依赖
node_modules/
.pnpm-store/
# 构建产物
dist/
build/
out/
# 环境配置
.env
.env.local
.env.*.local
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store
# 日志
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# 其他
*.bak
*.backup
*.old
+137
View File
@@ -0,0 +1,137 @@
#!/bin/bash
# PolyHermes 前端构建脚本
# 支持自定义后端 API 地址
set -e
# 颜色输出
RED='\033[0;31m'
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"
}
warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查 Node.js 环境
check_node() {
if ! command -v node &> /dev/null; then
error "Node.js 未安装,请先安装 Node.js 18+"
exit 1
fi
NODE_VERSION=$(node -v | cut -d'v' -f2 | cut -d'.' -f1)
if [ "$NODE_VERSION" -lt 18 ]; then
error "Node.js 版本过低,需要 Node.js 18+,当前版本: $(node -v)"
exit 1
fi
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)
# 构建 WebSocket URL
if [ "$PROTOCOL" = "https" ]; then
WS_PROTOCOL="wss"
else
WS_PROTOCOL="ws"
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
EOF
info "环境配置已创建: .env.production"
info " API URL: $API_URL"
info " WebSocket URL: $WS_URL"
}
# 构建应用
build_app() {
info "开始构建前端应用..."
# 检查依赖
if [ ! -d "node_modules" ]; then
info "安装依赖..."
npm install
fi
# 构建
info "执行构建..."
npm run build
if [ ! -d "dist" ]; then
error "构建失败,dist 目录不存在"
exit 1
fi
info "构建完成: dist/"
info "构建产物大小: $(du -sh dist | cut -f1)"
}
# 主函数
main() {
echo "=========================================="
echo " PolyHermes 前端构建脚本"
echo "=========================================="
echo ""
check_node
# 解析参数
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 自定义后端地址"
fi
create_env_file
build_app
echo ""
info "构建完成!"
info "部署方式:"
info " 1. 静态文件服务器:将 dist/ 目录部署到 Nginx、Apache 等"
info " 2. 使用 serve 预览:npx serve -s dist -l 3000"
}
main "$@"
+14 -1
View File
@@ -5,9 +5,22 @@ import { wsManager } from './websocket'
/**
* API 基础配置
* 支持通过环境变量 VITE_API_URL 配置后端地址
* 默认使用相对路径 /api(适用于同域部署)
* 如果设置了 VITE_API_URL,则使用完整 URL
*/
const getBaseURL = (): string => {
const envApiUrl = import.meta.env.VITE_API_URL
if (envApiUrl) {
// 如果设置了环境变量,使用完整 URL
return `${envApiUrl}/api`
}
// 否则使用相对路径(适用于开发环境代理或同域部署)
return '/api'
}
const apiClient: AxiosInstance = axios.create({
baseURL: '/api',
baseURL: getBaseURL(),
timeout: 30000,
headers: {
'Content-Type': 'application/json'
+16 -4
View File
@@ -325,16 +325,28 @@ class WebSocketManager {
/**
* 获取 WebSocket URL(带token认证)
* 支持通过环境变量 VITE_WS_URL 配置 WebSocket 地址
*/
private getWebSocketUrl(): string {
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
const host = window.location.host
const envWsUrl = import.meta.env.VITE_WS_URL
let wsBaseUrl: string
if (envWsUrl) {
// 如果设置了环境变量,使用完整 URL
wsBaseUrl = envWsUrl
} else {
// 否则使用相对路径(适用于开发环境代理或同域部署)
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
const host = window.location.host
wsBaseUrl = `${protocol}//${host}`
}
const token = this.getToken()
if (token) {
// 通过查询参数传递token
return `${protocol}//${host}/ws?token=${encodeURIComponent(token)}`
return `${wsBaseUrl}/ws?token=${encodeURIComponent(token)}`
}
return `${protocol}//${host}/ws`
return `${wsBaseUrl}/ws`
}
/**
+11
View File
@@ -0,0 +1,11 @@
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_API_URL?: string
readonly VITE_WS_URL?: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
+29 -14
View File
@@ -1,21 +1,36 @@
import { defineConfig } from 'vite'
import { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
server: {
port: 3000,
proxy: {
'/api': {
target: 'http://localhost:8000',
changeOrigin: true
},
'/ws': {
target: 'ws://localhost:8000',
ws: true,
changeOrigin: true
export default defineConfig(({ mode }) => {
// 加载环境变量
const env = loadEnv(mode, process.cwd(), '')
// 从环境变量获取 API 地址,默认使用 localhost:8000
const API_URL = env.VITE_API_URL || 'http://localhost:8000'
const WS_URL = env.VITE_WS_URL || 'ws://localhost:8000'
return {
plugins: [react()],
server: {
port: 3000,
proxy: {
'/api': {
target: API_URL,
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '/api')
},
'/ws': {
target: WS_URL,
ws: true,
changeOrigin: true
}
}
},
// 定义环境变量,在构建时注入
define: {
'import.meta.env.VITE_API_URL': JSON.stringify(API_URL),
'import.meta.env.VITE_WS_URL': JSON.stringify(WS_URL)
}
}
})