fix: fix bug docker
This commit is contained in:
@@ -18,6 +18,8 @@ app
|
|||||||
.git
|
.git
|
||||||
.gitignore
|
.gitignore
|
||||||
.github
|
.github
|
||||||
|
.agents
|
||||||
|
.codex
|
||||||
|
|
||||||
# Docker
|
# Docker
|
||||||
Dockerfile
|
Dockerfile
|
||||||
@@ -27,7 +29,6 @@ docker-compose*.yml
|
|||||||
# Env / secrets
|
# Env / secrets
|
||||||
.env
|
.env
|
||||||
.env.*
|
.env.*
|
||||||
!.env.production
|
|
||||||
build.sh
|
build.sh
|
||||||
|
|
||||||
# Editor / OS
|
# Editor / OS
|
||||||
|
|||||||
3
.env.example
Normal file
3
.env.example
Normal 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
3
.gitignore
vendored
@@ -11,6 +11,9 @@ node_modules
|
|||||||
dist
|
dist
|
||||||
dist-ssr
|
dist-ssr
|
||||||
*.local
|
*.local
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
|
||||||
# Editor directories and files
|
# Editor directories and files
|
||||||
.vscode/*
|
.vscode/*
|
||||||
|
|||||||
33
Dockerfile
33
Dockerfile
@@ -1,36 +1,31 @@
|
|||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1.7
|
||||||
|
|
||||||
# ---------- Build stage ----------
|
FROM node:22-alpine AS build
|
||||||
FROM node:20-alpine AS build
|
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Install dependencies (cached unless package files change)
|
|
||||||
COPY package.json package-lock.json ./
|
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 . .
|
COPY . .
|
||||||
|
|
||||||
# API base URL is baked in at build time (Vite inlines VITE_* vars).
|
# Vite embeds VITE_* variables in the static bundle during this stage.
|
||||||
# Override with: docker build --build-arg VITE_API_URL=https://api.example.com/api/v1 .
|
ARG VITE_API_URL=https://api.persain-game.com/api/v1
|
||||||
ARG VITE_API_URL
|
ENV VITE_API_URL=${VITE_API_URL}
|
||||||
ENV VITE_API_URL=$VITE_API_URL
|
|
||||||
|
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
# ---------- Runtime stage ----------
|
FROM nginxinc/nginx-unprivileged:1.28-alpine AS runtime
|
||||||
FROM nginx:alpine AS runtime
|
|
||||||
|
|
||||||
# SPA-aware nginx config
|
COPY --chown=nginx:nginx nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
COPY --from=build --chown=nginx:nginx /app/dist /usr/share/nginx/html
|
||||||
|
|
||||||
# Static build output
|
USER nginx
|
||||||
COPY --from=build /app/dist /usr/share/nginx/html
|
|
||||||
|
|
||||||
EXPOSE 80
|
EXPOSE 8080
|
||||||
|
|
||||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
|
||||||
CMD wget -q -O /dev/null http://127.0.0.1/ || exit 1
|
CMD wget -q -O /dev/null http://127.0.0.1:8080/healthz || exit 1
|
||||||
|
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
|
|||||||
78
README.md
78
README.md
@@ -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
|
پیشنیازها: Docker Engine و Docker Compose v2.
|
||||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
|
||||||
|
|
||||||
## Expanding the ESLint configuration
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
|
docker compose up --detach --build
|
||||||
|
|
||||||
- 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,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
|
سپس برنامه روی `http://localhost:8080` در دسترس است. برای مشاهده وضعیت و لاگها:
|
||||||
- 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
|
```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
17
build.sh
Normal file → Executable 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
|
docker compose config --quiet
|
||||||
|
docker compose up --detach --build --remove-orphans
|
||||||
echo $TOKEN | git pull https://$TOKEN@github.com/joshfe/persian-game.git
|
docker compose ps
|
||||||
|
|
||||||
npm i
|
|
||||||
npm run build
|
|
||||||
ls -al
|
|
||||||
|
|||||||
19
compose.yaml
Normal file
19
compose.yaml
Normal 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
|
||||||
25
nginx.conf
25
nginx.conf
@@ -1,10 +1,16 @@
|
|||||||
server {
|
server {
|
||||||
listen 80;
|
listen 8080;
|
||||||
server_name _;
|
server_name _;
|
||||||
|
server_tokens off;
|
||||||
|
|
||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
index index.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 ----
|
||||||
gzip on;
|
gzip on;
|
||||||
gzip_vary on;
|
gzip_vary on;
|
||||||
@@ -26,33 +32,32 @@ server {
|
|||||||
font/woff2
|
font/woff2
|
||||||
application/vnd.ms-fontobject;
|
application/vnd.ms-fontobject;
|
||||||
|
|
||||||
# ---- Hashed static assets: cache hard ----
|
location = /healthz {
|
||||||
# ^~ so this wins over the regex block below for Vite's fingerprinted files
|
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/ {
|
location ^~ /assets/ {
|
||||||
expires 1y;
|
expires 1y;
|
||||||
add_header Cache-Control "public, immutable";
|
|
||||||
try_files $uri =404;
|
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)$ {
|
location ~* \.(?:js|css|png|jpe?g|gif|webp|avif|svg|ico|woff2?|ttf|otf|eot|mp4|webm)$ {
|
||||||
expires 30d;
|
expires 30d;
|
||||||
add_header Cache-Control "public";
|
|
||||||
try_files $uri =404;
|
try_files $uri =404;
|
||||||
}
|
}
|
||||||
|
|
||||||
# ---- SPA fallback: unknown routes -> index.html (React Router) ----
|
|
||||||
location / {
|
location / {
|
||||||
try_files $uri $uri/ /index.html;
|
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 {
|
location = /index.html {
|
||||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
|
||||||
expires -1;
|
expires -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Don't log noise / don't cache the favicon aggressively is fine as-is
|
|
||||||
location = /favicon.ico {
|
location = /favicon.ico {
|
||||||
log_not_found off;
|
log_not_found off;
|
||||||
access_log off;
|
access_log off;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const useAxios = () => {
|
|||||||
|
|
||||||
const instance = axios.create({
|
const instance = axios.create({
|
||||||
baseURL:
|
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,
|
maxBodyLength: Infinity,
|
||||||
...(sessionStorage.getItem("shop_id") && {
|
...(sessionStorage.getItem("shop_id") && {
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
Reference in New Issue
Block a user