#!/usr/bin/env bash # انتشارِ فرانت روی سرور: گرفتنِ کدِ تازه، build، و جابه‌جاییِ بی‌وقفه‌ی dist. # # ./deploy.sh # شاخه‌ی main # ./deploy.sh # # build در dist.next ساخته می‌شود و فقط اگر کامل موفق شد جای dist را می‌گیرد؛ # پس سایت حتی چند ثانیه هم بی‌فایل نمی‌ماند. buildِ قبلی در dist.prev می‌ماند: # برگشت: rm -rf dist && mv dist.prev dist # # dist/config.js (آدرسِ API در زمانِ اجرا) اگر روی سرور دستی ویرایش شده باشد، # به buildِ تازه منتقل می‌شود تا با هر انتشار از دست نرود. set -euo pipefail cd "$(dirname "$0")" BRANCH="${1:-main}" step() { printf '\n\033[0;32m▸ %s\033[0m\n' "$1"; } fail() { printf '\033[0;31m✖ %s\033[0m\n' "$1" >&2; exit 1; } step "گرفتنِ کدِ تازه ($BRANCH)" git fetch origin "$BRANCH" || fail "به gitea وصل نشد." if [ -n "$(git status --porcelain --untracked-files=no)" ]; then mkdir -p .deploy-backups PATCH=".deploy-backups/local-changes-$(date +%Y%m%d-%H%M%S).patch" git diff > "$PATCH" printf ' تغییرِ دستی روی سرور بود؛ در %s ذخیره شد.\n' "$PATCH" fi git reset --hard "origin/$BRANCH" git log --oneline -1 step "نصبِ وابستگی‌ها" npm ci --no-audit --no-fund step "type-check و build" rm -rf dist.next npx tsc --noEmit || fail "type-check شکست خورد؛ سایت دست نخورد." npx vite build --outDir dist.next --emptyOutDir || fail "build شکست خورد؛ سایت دست نخورد." if [ -f dist/config.js ] && ! cmp -s dist/config.js public/config.js; then cp dist/config.js dist.next/config.js printf ' config.jsِ ویرایش‌شده‌ی سرور نگه داشته شد.\n' fi step "جابه‌جایی" rm -rf dist.prev [ -d dist ] && mv dist dist.prev mv dist.next dist API="$(grep -oh 'https\?://[a-zA-Z0-9.-]*/api' dist/assets/*.js | head -1)" printf ' منتشر شد. آدرسِ API در build: %s\n' "${API:-(هم‌دامنه /api یا config.js)}" printf ' کشِ آروان را برای index.html و config.js پاک کنید اگر تغییری دیده نشد.\n'