added dynamic configuration of API_URL to docker deployments.
Now it works with editing only .env file.
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
# Runtime Configuration Implementation Summary
|
||||
|
||||
## What Was Implemented
|
||||
|
||||
Enhanced the BaMoRT frontend to support runtime configuration for **both desktop (Wails) and web production** deployments, eliminating the need to rebuild when changing API URLs.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Desktop (Wails)
|
||||
- Uses Go bindings to read API URL from `.env` file at runtime
|
||||
- Method: `window['go']['main']['App']['GetAPIBaseURL']()`
|
||||
- Configuration: `desktop/.env` → `API_PORT` variable
|
||||
- No rebuild needed when changing port
|
||||
|
||||
### Web Production (NEW)
|
||||
Uses a **multi-strategy fallback system**:
|
||||
|
||||
1. **config.json** (Priority 1)
|
||||
- Loads `/config.json` from web root
|
||||
- Can be modified after deployment
|
||||
- Example: `{"apiBaseURL": "https://api.yourdomain.com"}`
|
||||
|
||||
2. **Auto-detection** (Priority 2)
|
||||
- Probes `/api/public/version` at same origin
|
||||
- Works automatically with reverse proxy setups
|
||||
- Detects if backend and frontend share same domain
|
||||
|
||||
3. **VITE_API_URL** (Priority 3)
|
||||
- Environment variable at build time
|
||||
- Used for development: `VITE_API_URL=http://localhost:8180`
|
||||
|
||||
4. **Same Origin Fallback** (Priority 4)
|
||||
- Uses `window.location.origin`
|
||||
- Assumes backend and frontend on same domain
|
||||
|
||||
## Files Modified
|
||||
|
||||
### Core Implementation
|
||||
- `/data/dev/bamort/frontend/src/utils/config.js` - Enhanced with multi-strategy config loading
|
||||
- `/data/dev/bamort/frontend/src/utils/api.js` - Uses dynamic baseURL (already done for desktop)
|
||||
- `/data/dev/bamort/desktop/main.go` - GetAPIBaseURL() Go binding (already done for desktop)
|
||||
|
||||
### Documentation
|
||||
- `/data/dev/bamort/frontend/RUNTIME_CONFIG.md` - Complete web configuration guide
|
||||
- `/data/dev/bamort/desktop/RUNTIME_CONFIG.md` - Desktop configuration guide (existing)
|
||||
|
||||
### Configuration Files
|
||||
- `/data/dev/bamort/frontend/public/config.json.example` - Template for deployment
|
||||
- `/data/dev/bamort/frontend/.gitignore` - Excludes `public/config.json` from git
|
||||
|
||||
## How It Works
|
||||
|
||||
### For Web Development
|
||||
```bash
|
||||
cd frontend
|
||||
VITE_API_URL=http://localhost:8180 npm run dev
|
||||
```
|
||||
|
||||
### For Web Production Deployment
|
||||
|
||||
**Option A: Using config.json (Recommended)**
|
||||
```bash
|
||||
# 1. Build once
|
||||
cd frontend && npm run build
|
||||
|
||||
# 2. Deploy dist/ to web server
|
||||
|
||||
# 3. Create config.json in web root
|
||||
cat > /var/www/bamort/config.json <<EOF
|
||||
{
|
||||
"apiBaseURL": "https://api.production.com"
|
||||
}
|
||||
EOF
|
||||
|
||||
# 4. Change API URL anytime without rebuild!
|
||||
```
|
||||
|
||||
**Option B: Reverse Proxy Setup**
|
||||
Example nginx configuration:
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name yourdomain.com;
|
||||
|
||||
# Frontend
|
||||
location / {
|
||||
root /var/www/bamort;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# Backend API
|
||||
location /api {
|
||||
proxy_pass http://localhost:8180;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
}
|
||||
```
|
||||
Frontend auto-detects and uses same origin.
|
||||
|
||||
**Option C: Build with Embedded URL**
|
||||
```bash
|
||||
VITE_API_URL=https://api.production.com npm run build
|
||||
```
|
||||
(Not recommended - requires rebuild for URL changes)
|
||||
|
||||
### For Desktop (Wails)
|
||||
```bash
|
||||
# 1. Build once
|
||||
cd desktop && wails build
|
||||
|
||||
# 2. Change port in .env (no rebuild!)
|
||||
echo "API_PORT=9000" > desktop/.env
|
||||
|
||||
# 3. Run app - uses new port automatically
|
||||
./desktop/build/bin/bamort
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
Open browser console when loading the app. Look for one of these messages:
|
||||
|
||||
**Desktop:**
|
||||
```
|
||||
Desktop app using API URL from config: http://localhost:8185
|
||||
```
|
||||
|
||||
**Web:**
|
||||
```
|
||||
Loaded API URL from config.json: https://api.yourdomain.com
|
||||
```
|
||||
or
|
||||
```
|
||||
Detected backend at same origin: https://yourdomain.com
|
||||
```
|
||||
or
|
||||
```
|
||||
Web app using VITE_API_URL: http://localhost:8180
|
||||
```
|
||||
or
|
||||
```
|
||||
Web app using same origin: https://yourdomain.com
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
✅ **No rebuild needed** for API URL changes in production web deployments
|
||||
✅ **Same build artifact** can be deployed to dev/staging/production
|
||||
✅ **Infrastructure-friendly** - works with reverse proxies, Docker, static hosting
|
||||
✅ **Flexible** - multiple configuration strategies with sensible fallbacks
|
||||
✅ **Dev-friendly** - VITE_API_URL still works for development
|
||||
✅ **Desktop-friendly** - reads .env at runtime (already implemented)
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
- [x] Frontend builds successfully (`npm run build`)
|
||||
- [x] Desktop app reads runtime config from .env
|
||||
- [ ] Web dev mode works with VITE_API_URL
|
||||
- [ ] Web production with config.json works
|
||||
- [ ] Web production with reverse proxy auto-detection works
|
||||
- [ ] Web production with same-origin fallback works
|
||||
|
||||
## Migration Path
|
||||
|
||||
**For existing deployments:**
|
||||
1. No changes needed! Current builds continue working
|
||||
2. To enable runtime config: Just add `config.json` to your web root
|
||||
3. Old builds with VITE_API_URL still work as fallback
|
||||
|
||||
**For new deployments:**
|
||||
1. Build once: `npm run build`
|
||||
2. Deploy `dist/` contents
|
||||
3. Add `config.json` with your API URL
|
||||
4. Done!
|
||||
@@ -32,7 +32,7 @@ func SetupGin(r *gin.Engine) {
|
||||
}
|
||||
corsConfig = cors.Config{
|
||||
AllowOrigins: allowedOrigins,
|
||||
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE"},
|
||||
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"},
|
||||
AllowHeaders: []string{"Origin", "Content-Type", "Authorization"},
|
||||
ExposeHeaders: []string{"Content-Length"},
|
||||
AllowCredentials: true,
|
||||
|
||||
+5
-5
@@ -1,9 +1,5 @@
|
||||
# Environment variables for Bamort development environment
|
||||
|
||||
# API Configuration
|
||||
# API_URL=http://localhost:8180
|
||||
|
||||
# Database Configuration (for development)
|
||||
DATABASE_TYPE=mysql
|
||||
DATABASE_URL=bamort:bG4)efozrc@tcp(mariadb-dev:3306)/bamort?charset=utf8mb4&parseTime=True&loc=Local
|
||||
|
||||
@@ -13,9 +9,13 @@ MARIADB_PASSWORD=bG4)efozrc
|
||||
MARIADB_DATABASE=bamort
|
||||
MARIADB_USER=bamort
|
||||
|
||||
# Frontend Configuration
|
||||
# API Configuration
|
||||
# API_URL is used by the frontend to connect to the backend
|
||||
# For dev environment with Vite dev server, this goes to VITE_API_URL
|
||||
API_URL=http://192.168.0.48:8180
|
||||
API_PORT=8180
|
||||
|
||||
# Frontend Configuration
|
||||
BASE_URL=http://localhost:5173
|
||||
TEMPLATES_DIR=./templates
|
||||
EXPORT_TEMP_DIR=./export_temp
|
||||
|
||||
+16
-3
@@ -1,9 +1,16 @@
|
||||
# Environment variables for Bamort production deployment
|
||||
# Copy this file to .env and adjust the values as needed
|
||||
# Copy this file to .env.dev or .env.prd and adjust the values as needed
|
||||
|
||||
#- API Configuration
|
||||
# ===== FRONTEND API CONFIGURATION =====
|
||||
# API_URL: The backend API endpoint that the frontend will use
|
||||
# For production: Use your public API domain (https://api.yourdomain.com)
|
||||
# For development: Use your local network IP (http://192.168.x.x:8180)
|
||||
#
|
||||
# IMPORTANT: After changing API_URL, just restart containers - NO REBUILD NEEDED!
|
||||
# Production: docker-compose -f docker-compose.yml restart frontend
|
||||
# Development: docker-compose -f docker-compose.dev.yml restart frontend-dev
|
||||
API_URL=https://backend.domain.de
|
||||
VITE_API_URL=https://backend.domain.de
|
||||
API_PORT=8180
|
||||
|
||||
#- Database Configuration Backend
|
||||
DATABASE_TYPE=mysql
|
||||
@@ -20,3 +27,9 @@ BASE_URL=https://frontend.domain.de
|
||||
TEMPLATES_DIR=./templates
|
||||
EXPORT_TEMP_DIR=./export_temp
|
||||
COMPOSE_PROJECT_NAME=bamort
|
||||
|
||||
# Mail Configuration (for development)
|
||||
MAIL_HOST=mail.server.de
|
||||
MAIL_PORT=465
|
||||
MAIL_USERNAME=bamort@server.de
|
||||
MAIL_PASSWORD=XXXZZZZZ.YYYXXX
|
||||
+4
-4
@@ -1,10 +1,10 @@
|
||||
# Environment variables for Bamort production environment
|
||||
|
||||
# API Configuration
|
||||
# API_URL is used by the frontend to generate config.json at container startup
|
||||
# Change this value and restart containers (no rebuild needed!)
|
||||
API_URL=https://bamort-api.trokan.de
|
||||
VITE_API_URL=https://bamort-api.trokan.de
|
||||
|
||||
# Database Configuration Backend
|
||||
API_PORT=8180
|
||||
DATABASE_TYPE=mysql
|
||||
#DATABASE_URL=bamort:bG4)efozrc@tcp(mariadb:3306)/bamort?charset=utf8mb4&parseTime=True&loc=Local
|
||||
|
||||
@@ -14,7 +14,7 @@ MARIADB_PASSWORD=bG4)efozrc
|
||||
MARIADB_DATABASE=bamort
|
||||
MARIADB_USER=bamort
|
||||
|
||||
API_PORT=8180
|
||||
# Frontend Configuration
|
||||
BASE_URL=https://bamort.trokan.de
|
||||
TEMPLATES_DIR=./templates
|
||||
EXPORT_TEMP_DIR=./export_temp
|
||||
|
||||
+12
-17
@@ -1,42 +1,37 @@
|
||||
# =========== 1) Build stage ===========
|
||||
FROM node:22-alpine AS build
|
||||
|
||||
# Accept build arguments for Vite environment variables
|
||||
ARG VITE_API_URL
|
||||
ARG VITE_BASE_URL
|
||||
ARG VITE_API_PORT
|
||||
|
||||
# Set them as environment variables for the build process
|
||||
ENV VITE_API_URL=$VITE_API_URL
|
||||
ENV VITE_BASE_URL=$VITE_BASE_URL
|
||||
ENV VITE_API_PORT=$VITE_API_PORT
|
||||
|
||||
# No build args needed - using runtime configuration instead
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Copy package files
|
||||
COPY package*.json ./
|
||||
|
||||
|
||||
# Install dependencies
|
||||
RUN npm install
|
||||
|
||||
# Copy the rest of the frontend code
|
||||
COPY . .
|
||||
|
||||
# Build the production bundle
|
||||
# Build the production bundle WITHOUT baked-in API URL
|
||||
# Runtime configuration will be generated from environment variables
|
||||
RUN npm run build
|
||||
|
||||
# =========== 2) Serve stage ===========
|
||||
FROM nginx:alpine
|
||||
|
||||
# Copy production build to Nginx html folder.
|
||||
# Adjust /usr/src/app/build -> /usr/src/app/dist if you’re using Angular/Vue
|
||||
#COPY --from=build /usr/src/app/build /usr/share/nginx/html
|
||||
# Copy production build to Nginx html folder
|
||||
COPY --from=build /usr/src/app/dist /usr/share/nginx/html
|
||||
|
||||
# Copy custom nginx configuration for SPA routing
|
||||
COPY --from=build /usr/src/app/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Copy entrypoint script that generates runtime config
|
||||
COPY --from=build /usr/src/app/docker-entrypoint.sh /docker-entrypoint.sh
|
||||
RUN chmod +x /docker-entrypoint.sh
|
||||
|
||||
# Expose HTTP port
|
||||
EXPOSE 80
|
||||
|
||||
# Run Nginx in foreground
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
# Use custom entrypoint that generates config.json from environment
|
||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||
|
||||
@@ -9,8 +9,12 @@ COPY package*.json ./
|
||||
# Install dependencies
|
||||
RUN npm install
|
||||
|
||||
# Copy entrypoint script that generates config.json
|
||||
COPY docker-dev-entrypoint.sh /docker-entrypoint.sh
|
||||
RUN chmod +x /docker-entrypoint.sh
|
||||
|
||||
# Expose Vite dev server port
|
||||
EXPOSE 5173
|
||||
|
||||
# Start development server with host binding for Docker
|
||||
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
|
||||
# Use entrypoint that generates config.json before starting Vite
|
||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||
|
||||
@@ -25,18 +25,12 @@ services:
|
||||
build:
|
||||
context: ../frontend
|
||||
dockerfile: ../docker/Dockerfile.frontend
|
||||
args:
|
||||
VITE_API_URL: ${API_URL:-https://bamort-api.trokan.de}
|
||||
VITE_BASE_URL: ${BASE_URL:-https://bamort.trokan.de}
|
||||
VITE_API_PORT: ${API_PORT:-443}
|
||||
container_name: bamort-frontend
|
||||
ports:
|
||||
- "8181:80"
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- VITE_API_URL=${API_URL:-https://bamort.trokan.de:8180}
|
||||
- VITE_BASE_URL=${BASE_URL:-https://bamort.trokan.de}
|
||||
- VITE_API_PORT=${API_PORT:-8180}
|
||||
- API_URL=${API_URL:-https://bamort-api.trokan.de}
|
||||
depends_on:
|
||||
- backend
|
||||
restart: unless-stopped
|
||||
|
||||
Executable
+35
@@ -0,0 +1,35 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# Generate config.json from VITE_API_URL for development
|
||||
# This makes the dev environment behave the same as production
|
||||
|
||||
CONFIG_FILE="/app/public/config.json"
|
||||
|
||||
echo "🔧 Generating development config.json..."
|
||||
|
||||
# Use VITE_API_URL from environment
|
||||
API_BASE_URL="${VITE_API_URL:-}"
|
||||
|
||||
if [ -z "$API_BASE_URL" ]; then
|
||||
echo "⚠️ VITE_API_URL not set, creating minimal config"
|
||||
cat > "$CONFIG_FILE" <<EOF
|
||||
{
|
||||
"_comment": "Development mode - VITE_API_URL will be used as fallback"
|
||||
}
|
||||
EOF
|
||||
else
|
||||
echo "✅ API URL configured: $API_BASE_URL"
|
||||
cat > "$CONFIG_FILE" <<EOF
|
||||
{
|
||||
"apiBaseURL": "$API_BASE_URL"
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
|
||||
echo "📄 Created config.json:"
|
||||
cat "$CONFIG_FILE"
|
||||
|
||||
# Start Vite dev server
|
||||
echo "🚀 Starting Vite dev server..."
|
||||
exec npm run dev -- --host 0.0.0.0
|
||||
@@ -0,0 +1,36 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# Generate config.json from environment variables at container startup
|
||||
# This allows runtime configuration without rebuilding the container
|
||||
|
||||
CONFIG_FILE="/usr/share/nginx/html/config.json"
|
||||
|
||||
echo "🔧 Generating frontend runtime configuration..."
|
||||
|
||||
# Use API_URL from environment, or fallback to same origin
|
||||
API_BASE_URL="${API_URL:-}"
|
||||
|
||||
if [ -z "$API_BASE_URL" ]; then
|
||||
echo "⚠️ API_URL not set, frontend will auto-detect or use same origin"
|
||||
# Create minimal config that triggers auto-detection
|
||||
cat > "$CONFIG_FILE" <<EOF
|
||||
{
|
||||
"_comment": "API_URL not configured, using auto-detection"
|
||||
}
|
||||
EOF
|
||||
else
|
||||
echo "✅ API URL configured: $API_BASE_URL"
|
||||
cat > "$CONFIG_FILE" <<EOF
|
||||
{
|
||||
"apiBaseURL": "$API_BASE_URL"
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
|
||||
echo "📄 Generated config.json:"
|
||||
cat "$CONFIG_FILE"
|
||||
|
||||
# Start nginx
|
||||
echo "🚀 Starting nginx..."
|
||||
exec nginx -g "daemon off;"
|
||||
+18
-1
@@ -11,16 +11,33 @@ fi
|
||||
# Gehe ins Docker-Verzeichnis
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# Load development environment variables
|
||||
if [ -f .env.dev ]; then
|
||||
echo "📝 Loading configuration from .env.dev"
|
||||
export $(grep -v '^#' .env.dev | xargs)
|
||||
else
|
||||
if [ -f .env ]; then
|
||||
echo "📝 Loading configuration from .env"
|
||||
export $(grep -v '^#' .env | xargs)
|
||||
else
|
||||
echo "⚠️ Warning: .env not found, using defaults"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Get current git commit
|
||||
export GIT_COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
|
||||
echo "📝 Git Commit: $GIT_COMMIT"
|
||||
|
||||
echo "📦 Building and starting development containers..."
|
||||
echo "🔧 Frontend will use API: ${API_URL:-http://localhost:8180}"
|
||||
|
||||
# Stoppe vorhandene Container
|
||||
docker-compose -f docker-compose.dev.yml down
|
||||
|
||||
# Baue und starte die Container
|
||||
docker-compose -f docker-compose.dev.yml up --build -d
|
||||
docker-compose -f docker-compose.dev.yml --env-file .env.dev up --build -d
|
||||
|
||||
echo "✅ Development environment started."
|
||||
echo "📱 Frontend: http://localhost:5173"
|
||||
echo "🔌 Backend: http://localhost:8180"
|
||||
echo "🗄️ phpMyAdmin: http://localhost:8081"
|
||||
|
||||
+23
-2
@@ -11,14 +11,35 @@ fi
|
||||
# Gehe ins Docker-Verzeichnis
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# Load production environment variables
|
||||
if [ -f .env.prd ]; then
|
||||
echo "📝 Loading configuration from .env.prd"
|
||||
export $(grep -v '^#' .env.prd | xargs)
|
||||
else
|
||||
if [ -f .env ]; then
|
||||
echo "📝 Loading configuration from .env"
|
||||
export $(grep -v '^#' .env | xargs)
|
||||
else
|
||||
echo "⚠️ Warning: .env not found, using defaults"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "📦 Building and starting production containers..."
|
||||
echo "🔧 Frontend will use API: ${API_URL:-https://bamort-api.trokan.de}"
|
||||
|
||||
# Build before stopping existing containers
|
||||
docker-compose -f docker-compose.yml build
|
||||
docker-compose -f docker-compose.yml --env-file .env.prd build
|
||||
|
||||
# Stoppe vorhandene Container
|
||||
docker-compose -f docker-compose.yml down
|
||||
|
||||
# Baue und starte die Container
|
||||
docker-compose -f docker-compose.yml up --build -d
|
||||
docker-compose -f docker-compose.yml --env-file .env.prd up -d
|
||||
|
||||
echo "✅ Production environment started."
|
||||
echo "📱 Frontend: http://localhost:8181"
|
||||
echo "🔌 Backend: http://localhost:8182"
|
||||
echo ""
|
||||
echo "💡 To change API URL: Edit .env.prd and run:"
|
||||
echo " docker-compose -f docker-compose.yml restart frontend"
|
||||
echo " (No rebuild needed!)"
|
||||
@@ -13,6 +13,13 @@ dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Runtime configuration (use config.json.example as template)
|
||||
public/config.json
|
||||
|
||||
# Docker entrypoint scripts (copied from ../docker/ during build)
|
||||
docker-entrypoint.sh
|
||||
docker-dev-entrypoint.sh
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"apiBaseURL": "http://localhost:8180",
|
||||
"_comment": "This file can be modified at deployment without rebuilding. Copy to config.json and adjust apiBaseURL for your environment."
|
||||
}
|
||||
@@ -4,38 +4,65 @@
|
||||
* For desktop builds (Wails), reads the API base URL from the Go backend
|
||||
* to allow runtime configuration via .env without rebuilding.
|
||||
*
|
||||
* For web builds, uses VITE_API_URL environment variable.
|
||||
* For web builds, uses runtime config.json or auto-detection:
|
||||
* 1. Try to load /config.json (can be modified at deployment without rebuild)
|
||||
* 2. Try to detect backend at same origin (production reverse proxy setup)
|
||||
* 3. Fall back to VITE_API_URL (development) or same origin
|
||||
*/
|
||||
|
||||
let cachedAPIBaseURL = null
|
||||
|
||||
/**
|
||||
* Check if we're running in a Wails desktop app
|
||||
* Try to load configuration from /config.json
|
||||
*/
|
||||
function isWailsApp() {
|
||||
return typeof window !== 'undefined' &&
|
||||
window['go'] !== undefined &&
|
||||
window['go']['main'] !== undefined &&
|
||||
window['go']['main']['App'] !== undefined
|
||||
async function loadConfigFile() {
|
||||
try {
|
||||
const response = await fetch('/config.json', {
|
||||
cache: 'no-cache',
|
||||
headers: { 'Accept': 'application/json' }
|
||||
})
|
||||
if (response.ok) {
|
||||
// Check if response is actually JSON (not HTML from SPA fallback)
|
||||
const contentType = response.headers.get('content-type')
|
||||
if (contentType && contentType.includes('application/json')) {
|
||||
const config = await response.json()
|
||||
if (config.apiBaseURL) {
|
||||
console.log('Loaded API URL from config.json:', config.apiBaseURL)
|
||||
return config.apiBaseURL
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// config.json doesn't exist or is invalid, that's okay
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for Wails to initialize (max 3 seconds)
|
||||
* Try to detect backend at same origin (production setup)
|
||||
*/
|
||||
async function waitForWails(maxAttempts = 30) {
|
||||
for (let i = 0; i < maxAttempts; i++) {
|
||||
if (isWailsApp()) {
|
||||
return true
|
||||
async function detectBackendAtOrigin() {
|
||||
try {
|
||||
const origin = window.location.origin
|
||||
const response = await fetch(`${origin}/api/public/version`, {
|
||||
method: 'GET',
|
||||
cache: 'no-cache',
|
||||
signal: AbortSignal.timeout(2000) // 2 second timeout
|
||||
})
|
||||
if (response.ok) {
|
||||
console.log('Detected backend at same origin:', origin)
|
||||
return origin
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, 100))
|
||||
} catch (error) {
|
||||
// Backend not at same origin, that's okay
|
||||
}
|
||||
return false
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the API base URL dynamically
|
||||
* - In Wails desktop app: calls Go backend to get configured URL
|
||||
* - In web app: uses VITE_API_URL or defaults to production API
|
||||
* - In web app: tries config.json, auto-detection, or VITE_API_URL
|
||||
*/
|
||||
export async function getAPIBaseURL() {
|
||||
// Return cached value if available
|
||||
@@ -43,34 +70,58 @@ export async function getAPIBaseURL() {
|
||||
return cachedAPIBaseURL
|
||||
}
|
||||
|
||||
// Check if this looks like a desktop environment
|
||||
const isDesktop = typeof window !== 'undefined' &&
|
||||
(window.location.protocol === 'wails:' ||
|
||||
window.location.hostname === 'wails.localhost')
|
||||
|
||||
// Wails desktop app - wait for Wails to be ready
|
||||
if (isDesktop || typeof window !== 'undefined' && window['go']) {
|
||||
const wailsReady = await waitForWails()
|
||||
|
||||
if (wailsReady) {
|
||||
// Try Wails desktop app first (with timeout)
|
||||
if (typeof window !== 'undefined' && window['go']) {
|
||||
// Wait up to 3 seconds for Wails bindings to be ready
|
||||
for (let i = 0; i < 30; i++) {
|
||||
try {
|
||||
// Access Wails Go bindings via window object
|
||||
if (window['go']?.['main']?.['App']?.['GetAPIBaseURL']) {
|
||||
const url = await window['go']['main']['App']['GetAPIBaseURL']()
|
||||
cachedAPIBaseURL = url
|
||||
console.log('Desktop app using API URL from config:', url)
|
||||
return url
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to get API URL from Wails:', error)
|
||||
// Fallback to localhost for desktop
|
||||
break
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, 100))
|
||||
}
|
||||
|
||||
// Wails detected but binding failed - use desktop fallback
|
||||
cachedAPIBaseURL = 'http://localhost:8185'
|
||||
console.log('Desktop app using fallback:', cachedAPIBaseURL)
|
||||
return cachedAPIBaseURL
|
||||
}
|
||||
|
||||
// Web app - try multiple strategies
|
||||
|
||||
// Strategy 1: Load from config.json (can be modified at deployment)
|
||||
const configFileURL = await loadConfigFile()
|
||||
if (configFileURL) {
|
||||
cachedAPIBaseURL = configFileURL
|
||||
return cachedAPIBaseURL
|
||||
}
|
||||
|
||||
// Strategy 2: Check if backend is at same origin (production reverse proxy)
|
||||
if (window.location.hostname !== 'localhost' && window.location.hostname !== '127.0.0.1') {
|
||||
const sameOriginURL = await detectBackendAtOrigin()
|
||||
if (sameOriginURL) {
|
||||
cachedAPIBaseURL = sameOriginURL
|
||||
return cachedAPIBaseURL
|
||||
}
|
||||
}
|
||||
|
||||
// Strategy 3: Use VITE_API_URL (development) or fallback to same origin
|
||||
if (import.meta.env.VITE_API_URL) {
|
||||
cachedAPIBaseURL = import.meta.env.VITE_API_URL
|
||||
console.log('Web app using VITE_API_URL:', cachedAPIBaseURL)
|
||||
} else {
|
||||
// Final fallback: assume same origin for production
|
||||
cachedAPIBaseURL = window.location.origin
|
||||
console.log('Web app using same origin:', cachedAPIBaseURL)
|
||||
}
|
||||
|
||||
// Web app - use environment variable or production default
|
||||
cachedAPIBaseURL = import.meta.env.VITE_API_URL || 'https://bamort-api.trokan.de'
|
||||
console.log('Web app using API URL:', cachedAPIBaseURL)
|
||||
return cachedAPIBaseURL
|
||||
}
|
||||
|
||||
@@ -79,4 +130,5 @@ export async function getAPIBaseURL() {
|
||||
*/
|
||||
export function isDesktopMode() {
|
||||
return isWailsApp()
|
||||
}
|
||||
}typeof window !== 'undefined' &&
|
||||
window['go']?.['main']?.['App'] !== undefined
|
||||
|
||||
Reference in New Issue
Block a user