fix: fix bug docker

This commit is contained in:
2026-09-02 20:29:41 +03:30
parent c5bfa5544c
commit aeefe075dd
9 changed files with 118 additions and 65 deletions

View File

@@ -18,6 +18,8 @@ app
.git
.gitignore
.github
.agents
.codex
# Docker
Dockerfile
@@ -27,7 +29,6 @@ docker-compose*.yml
# Env / secrets
.env
.env.*
!.env.production
build.sh
# Editor / OS

3
.env.example Normal file
View File

@@ -0,0 +1,3 @@
APP_PORT=8080
VITE_API_URL=https://api.persain-game.com/api/v1
PERSIAN_GAME_IMAGE=persian-game:local

3
.gitignore vendored
View File

@@ -11,6 +11,9 @@ node_modules
dist
dist-ssr
*.local
.env
.env.*
!.env.example
# Editor directories and files
.vscode/*

View File

@@ -1,36 +1,31 @@
# syntax=docker/dockerfile:1
# syntax=docker/dockerfile:1.7
# ---------- Build stage ----------
FROM node:20-alpine AS build
FROM node:22-alpine AS build
WORKDIR /app
# Install dependencies (cached unless package files change)
COPY package.json package-lock.json ./
RUN npm ci
RUN --mount=type=cache,target=/root/.npm \
npm ci --no-audit --no-fund
# Build the app
COPY . .
# API base URL is baked in at build time (Vite inlines VITE_* vars).
# Override with: docker build --build-arg VITE_API_URL=https://api.example.com/api/v1 .
ARG VITE_API_URL
ENV VITE_API_URL=$VITE_API_URL
# Vite embeds VITE_* variables in the static bundle during this stage.
ARG VITE_API_URL=https://api.persain-game.com/api/v1
ENV VITE_API_URL=${VITE_API_URL}
RUN npm run build
# ---------- Runtime stage ----------
FROM nginx:alpine AS runtime
FROM nginxinc/nginx-unprivileged:1.28-alpine AS runtime
# SPA-aware nginx config
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --chown=nginx:nginx nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build --chown=nginx:nginx /app/dist /usr/share/nginx/html
# Static build output
COPY --from=build /app/dist /usr/share/nginx/html
USER nginx
EXPOSE 80
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget -q -O /dev/null http://127.0.0.1/ || exit 1
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
CMD wget -q -O /dev/null http://127.0.0.1:8080/healthz || exit 1
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -1,30 +1,60 @@
# React + TypeScript + Vite
# Persian Game frontend
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
رابط کاربری React + TypeScript این پروژه با Vite ساخته و در محیط production توسط Nginx سرو می‌شود.
Currently, two official plugins are available:
## اجرای Docker
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
پیش‌نیازها: Docker Engine و Docker Compose v2.
## Expanding the ESLint configuration
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
- Configure the top-level `parserOptions` property like this:
```js
export default {
// other rules...
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: ['./tsconfig.json', './tsconfig.node.json'],
tsconfigRootDir: __dirname,
},
}
```bash
cp .env.example .env
docker compose up --detach --build
```
- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
سپس برنامه روی `http://localhost:8080` در دسترس است. برای مشاهده وضعیت و لاگ‌ها:
```bash
docker compose ps
docker compose logs --follow web
```
برای توقف برنامه:
```bash
docker compose down
```
اسکریپت زیر نیز Compose را اعتبارسنجی، image را build و سرویس را اجرا می‌کند:
```bash
./build.sh
```
## تنظیمات
مقادیر قابل تنظیم در `.env`:
- `APP_PORT`: پورت میزبان؛ مقدار پیش‌فرض `8080` است.
- `VITE_API_URL`: آدرس کامل API؛ مقدار پیش‌فرض `https://api.persain-game.com/api/v1` است.
- `PERSIAN_GAME_IMAGE`: نام و tag ایمیج ساخته‌شده.
متغیر `VITE_API_URL` هنگام build داخل فایل‌های استاتیک قرار می‌گیرد. پس از تغییر آن باید image را دوباره build کنید:
```bash
docker compose build --no-cache web
docker compose up --detach web
```
## توسعه محلی بدون Docker
```bash
npm ci
npm run dev
```
بررسی production build و lint:
```bash
npm run build
npm run lint
```

17
build.sh Normal file → Executable file
View File

@@ -1,13 +1,10 @@
#!/bin/bash
#!/usr/bin/env sh
REPO_DIR="/var/www/html/persian-game/"
set -eu
TOKEN="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"
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
cd "$SCRIPT_DIR"
cd $REPO_DIR
echo $TOKEN | git pull https://$TOKEN@github.com/joshfe/persian-game.git
npm i
npm run build
ls -al
docker compose config --quiet
docker compose up --detach --build --remove-orphans
docker compose ps

19
compose.yaml Normal file
View File

@@ -0,0 +1,19 @@
services:
web:
image: ${PERSIAN_GAME_IMAGE:-persian-game:local}
build:
context: .
target: runtime
args:
VITE_API_URL: ${VITE_API_URL:-https://api.persain-game.com/api/v1}
ports:
- "${APP_PORT:-8080}:8080"
restart: unless-stopped
read_only: true
tmpfs:
- /tmp:size=16m,mode=1777
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
stop_grace_period: 10s

View File

@@ -1,10 +1,16 @@
server {
listen 80;
listen 8080;
server_name _;
server_tokens off;
root /usr/share/nginx/html;
index index.html;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
# ---- gzip ----
gzip on;
gzip_vary on;
@@ -26,33 +32,32 @@ server {
font/woff2
application/vnd.ms-fontobject;
# ---- Hashed static assets: cache hard ----
# ^~ so this wins over the regex block below for Vite's fingerprinted files
location = /healthz {
access_log off;
default_type text/plain;
return 200 "ok\n";
}
# Vite fingerprints files under /assets, so they can be cached for a year.
location ^~ /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
try_files $uri =404;
}
# ---- Other static files by extension ----
location ~* \.(?:js|css|png|jpe?g|gif|webp|avif|svg|ico|woff2?|ttf|otf|eot|mp4|webm)$ {
expires 30d;
add_header Cache-Control "public";
try_files $uri =404;
}
# ---- SPA fallback: unknown routes -> index.html (React Router) ----
location / {
try_files $uri $uri/ /index.html;
}
# index.html must never be cached, so new deploys are picked up
# Always revalidate the entrypoint so deployments are picked up immediately.
location = /index.html {
add_header Cache-Control "no-cache, no-store, must-revalidate";
expires -1;
}
# Don't log noise / don't cache the favicon aggressively is fine as-is
location = /favicon.ico {
log_not_found off;
access_log off;

View File

@@ -9,7 +9,7 @@ const useAxios = () => {
const instance = axios.create({
baseURL:
import.meta.env.VITE_API_URL ?? "https://api.persain-game.com/api/v1",
import.meta.env.VITE_API_URL || "https://api.persain-game.com/api/v1",
maxBodyLength: Infinity,
...(sessionStorage.getItem("shop_id") && {
headers: {