Desktop app dynamic config of API Port (#40)

* added dynamic configuration of Port in Desktop app
* added dynamic configuration of API_URL to docker deployments.

Now it works with editing only .env file.
This commit is contained in:
Bardioc26
2026-02-27 11:55:30 +01:00
committed by GitHub
parent bb9ef4f77e
commit 261a6294cb
24 changed files with 597 additions and 55 deletions
+174
View File
@@ -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!
+1 -1
View File
@@ -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,
+64
View File
@@ -0,0 +1,64 @@
# Desktop Runtime Configuration
The BaMoRT desktop app now uses **runtime configuration** for the API port, meaning you can change the port in the `.env` file without rebuilding the app.
## How It Works
### Backend (Go)
- **[desktop/main.go](desktop/main.go)**: The `App.GetAPIBaseURL()` method reads the configured port from `config.Cfg` and returns the full API URL
- This method is bound to the frontend via Wails, making it callable from JavaScript
### Frontend (Vue/JS)
- **[frontend/src/utils/config.js](frontend/src/utils/config.js)**: Detects if running in Wails and calls the Go backend to get the API URL at runtime
- **[frontend/src/utils/api.js](frontend/src/utils/api.js)**: Uses the dynamic config instead of a hardcoded VITE_API_URL
- The API URL is cached after first retrieval for performance
### Build Process
- **[frontend/package.json](frontend/package.json)**: The `build:desktop` script no longer hardcodes `VITE_API_URL`
- The frontend bundle is now port-agnostic
## Usage
### Change the API Port
1. Edit `desktop/.env`:
```env
API_PORT=8185 # Change to any port you want
```
2. Run the app - no rebuild needed!
```bash
./desktop/build/bin/bamort
```
The frontend will automatically connect to the configured port.
### Environment Detection
The config system automatically detects the environment:
- **Desktop (Wails)**: Calls `window.go.main.App.GetAPIBaseURL()` to get the URL from Go backend
- **Web (Development)**: Uses `import.meta.env.VITE_API_URL` from Vite
- **Web (Production)**: Defaults to `https://bamort-api.trokan.de`
## Fallback Behavior
If the desktop app can't reach the Go backend (shouldn't happen), it falls back to `http://localhost:8185`.
## Benefits
✅ Change API port without rebuilding
✅ Faster iteration during development
✅ Same binary works with different configurations
✅ Cleaner separation of config from code
## Technical Details
**Request Flow:**
1. Frontend makes API request
2. Axios interceptor checks if `baseURL` is set
3. If not set, calls `getAPIBaseURL()` from config.js
4. Config.js detects Wails environment via `window.go`
5. Calls Go backend's `GetAPIBaseURL()` method
6. Caches the result for subsequent requests
7. Request proceeds with correct baseURL
+13 -3
View File
@@ -1,6 +1,6 @@
// BaMoRT Desktop application entry point.
// Uses Wails v2 to wrap the existing Gin HTTP server in a native desktop window.
// The backend runs on localhost:8180 (SQLite); the WebView loads the bundled frontend.
// The backend runs on localhost:8185 (SQLite); the WebView loads the bundled frontend.
package main
import (
@@ -56,8 +56,15 @@ func (a *App) startup(ctx context.Context) {
startGinServer()
}
// GetAPIBaseURL returns the HTTP server address for the frontend to connect to.
// This allows the API port to be configured at runtime via .env without rebuilding.
func (a *App) GetAPIBaseURL() string {
// GetServerAddress returns ":port", so we need to add localhost
return "http://localhost" + config.Cfg.GetServerAddress()
}
// startGinServer initialises the database, runs migrations, and starts the
// Gin HTTP server on the configured port (default 8180) in a goroutine.
// Gin HTTP server on the configured port (default 8185) in a goroutine.
func startGinServer() {
cfg := config.Cfg
@@ -131,7 +138,7 @@ func main() {
_ = os.Setenv("ENVIRONMENT", "desktop")
}
if os.Getenv("API_PORT") == "" {
_ = os.Setenv("API_PORT", "8180")
_ = os.Setenv("API_PORT", "8185")
}
if os.Getenv("TEMPLATES_DIR") == "" {
_ = os.Setenv("TEMPLATES_DIR", "./templates")
@@ -158,6 +165,9 @@ func main() {
MinWidth: 1024,
MinHeight: 768,
OnStartup: app.startup,
Bind: []interface{}{
app,
},
AssetServer: &assetserver.Options{
Assets: frontendFS,
},
+5 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 youre 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"]
+6 -2
View File
@@ -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"]
+1 -7
View File
@@ -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
+35
View File
@@ -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
+36
View File
@@ -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
View File
@@ -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"
+24 -3
View File
@@ -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 "✅ 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!)"
+7
View File
@@ -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
+1 -1
View File
@@ -7,7 +7,7 @@
"scripts": {
"dev": "vite",
"build": "vite build",
"build:desktop": "DESKTOP_BUILD=1 VITE_API_URL=http://localhost:8180 vite build",
"build:desktop": "DESKTOP_BUILD=1 vite build",
"preview": "vite preview"
},
"dependencies": {
+1 -1
View File
@@ -1 +1 @@
a98925179cb067ef9c9e5871faa6f8c7
705a38c2f133892600ec967917c4d556
+4
View File
@@ -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."
}
+26 -5
View File
@@ -1,12 +1,33 @@
import axios from 'axios'
import { getAPIBaseURL } from './config'
const API = axios.create({
baseURL: import.meta.env.VITE_API_URL || 'https://bamort-api.trokan.de', // Use env variable with fallback
})
// Create API instance without baseURL - will be set dynamically
const API = axios.create({})
// Request interceptor to add auth token
let baseURLPromise = null
let baseURLResolved = false
// Get base URL (cached after first call)
async function ensureBaseURL() {
if (baseURLResolved) {
return
}
if (!baseURLPromise) {
baseURLPromise = getAPIBaseURL()
}
const baseURL = await baseURLPromise
API.defaults.baseURL = baseURL
baseURLResolved = true
}
// Request interceptor to add auth token and ensure baseURL is set
API.interceptors.request.use(
(config) => {
async (config) => {
// Ensure baseURL is set before request
await ensureBaseURL()
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
+134
View File
@@ -0,0 +1,134 @@
/**
* Runtime configuration for BaMoRT frontend
*
* 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 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
/**
* Try to load configuration from /config.json
*/
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
}
/**
* Try to detect backend at same origin (production setup)
*/
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
}
} catch (error) {
// Backend not at same origin, that's okay
}
return null
}
/**
* Get the API base URL dynamically
* - In Wails desktop app: calls Go backend to get configured URL
* - In web app: tries config.json, auto-detection, or VITE_API_URL
*/
export async function getAPIBaseURL() {
// Return cached value if available
if (cachedAPIBaseURL) {
return cachedAPIBaseURL
}
// 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 {
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)
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)
}
return cachedAPIBaseURL
}
/**
* Check if running in desktop mode (Wails)
*/
export function isDesktopMode() {
return isWailsApp()
}typeof window !== 'undefined' &&
window['go']?.['main']?.['App'] !== undefined
+2 -1
View File
@@ -44,6 +44,7 @@
</style>
<script>
import { getAPIBaseURL } from '../utils/config'
import axios from 'axios'
import { getVersion, getGitCommit } from '../version'
@@ -80,7 +81,7 @@ export default {
methods: {
async fetchBackendVersion() {
try {
const apiUrl = import.meta.env.VITE_API_URL || 'http://localhost:8180'
const apiUrl = await getAPIBaseURL()
const response = await axios.get(`${apiUrl}/api/public/version`)
if (response.data) {
+2 -1
View File
@@ -115,6 +115,7 @@
</template>
<script>
import { getAPIBaseURL } from '../utils/config'
import axios from 'axios'
import { getVersion, getGitCommit } from '../version'
@@ -157,7 +158,7 @@ export default {
methods: {
async fetchBackendVersion() {
try {
const apiUrl = import.meta.env.VITE_API_URL || 'http://localhost:8180'
const apiUrl = await getAPIBaseURL()
const response = await axios.get(`${apiUrl}/api/public/systeminfo`)
if (response.data) {
+4
View File
@@ -0,0 +1,4 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
export function GetAPIBaseURL():Promise<string>;
+7
View File
@@ -0,0 +1,7 @@
// @ts-check
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
export function GetAPIBaseURL() {
return window['go']['main']['App']['GetAPIBaseURL']();
}