fix: fix bug docker
This commit is contained in:
@@ -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
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-ssr
|
||||
*.local
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
|
||||
33
Dockerfile
33
Dockerfile
@@ -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;"]
|
||||
|
||||
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
|
||||
- [@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
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
|
||||
|
||||
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
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 {
|
||||
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;
|
||||
|
||||
@@ -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: {
|
||||
|
||||
Reference in New Issue
Block a user