Skip to content

Commit 22d22cb

Browse files
committed
Add Docker support and runtime configuration for frontend application
1 parent 2d6827c commit 22d22cb

8 files changed

Lines changed: 146 additions & 7 deletions

File tree

.github/workflows/build.yml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Build and Push Frontend
2+
3+
on:
4+
# 在推送到 main 或 dev 分支时触发
5+
push:
6+
branches: ["main", "dev"]
7+
# 在向 main 或 dev 分支发起 Pull Request 时触发
8+
pull_request:
9+
branches: ["main", "dev"]
10+
# 允许手动触发
11+
workflow_dispatch:
12+
13+
jobs:
14+
build-and-push:
15+
runs-on: ubuntu-latest
16+
17+
permissions:
18+
contents: read
19+
packages: write # 需要写权限来推送镜像到 ghcr.io
20+
21+
steps:
22+
- name: Checkout repository
23+
uses: actions/checkout@v4
24+
25+
- name: Set up pnpm
26+
uses: pnpm/action-setup@v4
27+
28+
- name: Set up Node.js
29+
uses: actions/setup-node@v4
30+
with:
31+
node-version: "20"
32+
cache: "pnpm" # 为 pnpm 设置缓存
33+
34+
- name: Login to GitHub Container Registry
35+
uses: docker/login-action@v3
36+
with:
37+
registry: ghcr.io
38+
username: ${{ github.actor }}
39+
password: ${{ secrets.GITHUB_TOKEN }}
40+
41+
- name: Docker meta for frontend
42+
id: meta_frontend
43+
uses: docker/metadata-action@v5
44+
with:
45+
images: ghcr.io/${{ github.repository }}/snake-frontend
46+
47+
- name: Set up Docker Buildx
48+
uses: docker/setup-buildx-action@v3
49+
50+
- name: Build and push Docker image
51+
uses: docker/build-push-action@v6
52+
with:
53+
context: ./frontend # Dockerfile 所在的上下文路径
54+
file: ./frontend/Dockerfile # Dockerfile 的具体路径
55+
push: ${{ github.event_name == 'push' }} # 仅在 push 事件时推送到 ghcr.io
56+
tags: ${{ steps.meta_frontend.outputs.tags }}
57+
labels: ${{ steps.meta_frontend.outputs.labels }}
58+
cache-from: type=gha
59+
cache-to: type=gha,mode=max

Dockerfile

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# ---- Stage 1: Build Stage ----
2+
FROM node:22-alpine AS builder
3+
WORKDIR /app
4+
RUN npm install -g pnpm@9.12.2
5+
COPY package.json pnpm-lock.yaml* ./
6+
RUN pnpm install --frozen-lockfile
7+
COPY . .
8+
RUN pnpm build
9+
10+
# ---- Stage 2: Production Stage ----
11+
FROM nginx:stable-alpine
12+
COPY nginx.conf /etc/nginx/conf.d/default.conf
13+
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
14+
RUN chmod +x /usr/local/bin/entrypoint.sh
15+
COPY --from=builder /app/dist /usr/share/nginx/html
16+
EXPOSE 80
17+
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
18+
CMD ["nginx", "-g", "daemon off;"]

entrypoint.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/bin/sh
2+
ROOT_DIR=/usr/share/nginx/html
3+
VITE_API_URL=${VITE_API_URL:-"http://localhost:8080/api/cheese-auth"}
4+
VITE_SANDBOX_URL=${VITE_SANDBOX_URL:-"http://localhost:8080/api/sandbox"}
5+
6+
echo "window.runtimeConfig = { VITE_API_URL: '${VITE_API_URL}', VITE_SANDBOX_URL: '${VITE_SANDBOX_URL}' };" > ${ROOT_DIR}/config.js
7+
echo "Generated ${ROOT_DIR}/config.js with API URL: ${VITE_API_URL}"
8+
9+
exec "$@"

index.html

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,16 @@
33
<head>
44
<meta charset="UTF-8" />
55
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
6-
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" integrity="sha512-Evv84Mr4kqVGRNSgIGL/F/aIDqQb7xQ2vcrdIwxfjThSH8CSR7PBEakCr51Ck+w+/U6swU2Im1vVX0SVk9ABhg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
6+
<link
7+
rel="stylesheet"
8+
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css"
9+
integrity="sha512-Evv84Mr4kqVGRNSgIGL/F/aIDqQb7xQ2vcrdIwxfjThSH8CSR7PBEakCr51Ck+w+/U6swU2Im1vVX0SVk9ABhg=="
10+
crossorigin="anonymous"
11+
referrerpolicy="no-referrer"
12+
/>
713
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
814
<title>蛇王争霸 - 中国人民大学信息学院</title>
15+
<script src="/config.js"></script>
916
</head>
1017
<body>
1118
<div id="app"></div>

nginx.conf

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
server {
2+
# 监听 80 端口
3+
listen 80;
4+
5+
# 设置网站的根目录,指向我们从构建阶段复制过来的文件
6+
root /usr/share/nginx/html;
7+
8+
# 默认首页文件
9+
index index.html;
10+
11+
# 核心配置:处理所有请求
12+
location / {
13+
# try_files 会按顺序尝试查找文件:
14+
# 1. $uri: 查找与请求 URI 完全匹配的文件 (例如 /assets/logo.png)
15+
# 2. $uri/: 查找与请求 URI 匹配的目录 (例如 /admin/)
16+
# 3. /index.html: 如果上面都找不到,就返回根目录下的 index.html 文件
17+
#
18+
# 这一行是实现前端路由(History模式)的关键。
19+
# 它确保了所有未匹配到静态资源的请求都由 Vue 应用来接管处理。
20+
try_files $uri $uri/ /index.html;
21+
}
22+
23+
# 可选:为静态资源添加更长的浏览器缓存,提升性能
24+
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
25+
expires 1y;
26+
add_header Cache-Control "public";
27+
}
28+
}

public/config.js

Whitespace-only changes.

src/runtime-config.d.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// src/runtime-config.d.ts
2+
3+
// 扩展全局的 Window 接口
4+
declare global {
5+
interface Window {
6+
// 定义 runtimeConfig 对象的结构和类型
7+
runtimeConfig: {
8+
VITE_API_URL: string;
9+
VITE_SANDBOX_URL: string;
10+
};
11+
}
12+
}
13+
14+
// 导出一个空对象以确保该文件被视为一个模块
15+
export {};

src/services/httpClient.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import axios, { AxiosInstance, InternalAxiosRequestConfig } from "axios";
22
import router from "../router";
33

4-
// 基础API URL
5-
const API_URL =
6-
import.meta.env.VITE_API_URL || "http://localhost:8080/api/cheese-auth";
7-
// 沙盒API URL
8-
const SANDBOX_URL =
9-
import.meta.env.VITE_SANDBOX_URL || "http://localhost:8080/api/sandbox";
4+
const runtimeConfig = window.runtimeConfig || {
5+
VITE_API_URL:
6+
import.meta.env.VITE_API_URL || "http://localhost:8080/api/cheese-auth",
7+
VITE_SANDBOX_URL:
8+
import.meta.env.VITE_SANDBOX_URL || "http://localhost:8080/api/sandbox",
9+
};
10+
11+
const API_URL = runtimeConfig.VITE_API_URL;
12+
const SANDBOX_URL = runtimeConfig.VITE_SANDBOX_URL;
1013

1114
// 创建主API客户端实例
1215
export const apiClient = axios.create({

0 commit comments

Comments
 (0)