feat: basePath-Konfiguration von .env in config.json verschoben

basePath wird jetzt in config.json gepflegt statt als NEXT_PUBLIC_BASE_PATH in .env.*
Alle relevanten Code-Stellen lesen basePath dynamisch aus config.json
Dokumentation und Beispiele in Markdown-Dateien entsprechend angepasst
Erhöhte Flexibilität für Deployments ohne Rebuild
This commit is contained in:
ISA
2025-08-20 08:42:24 +02:00
parent bf4fc95b8e
commit 9a2b438eaf
19 changed files with 135 additions and 47 deletions

View File

@@ -20,9 +20,8 @@ NEXT_PUBLIC_USE_MOCKS=true
# Ein Unterordner in der dort hinter liegenden Ordnerstruktur (z.B. http://talasserver/talas5/nodemap/api/talas_v5_DB/ usw.) # Ein Unterordner in der dort hinter liegenden Ordnerstruktur (z.B. http://talasserver/talas5/nodemap/api/talas_v5_DB/ usw.)
# kann bleiben da der Kunde diesen Unterordner talas:v5_db nicht ändert. # kann bleiben da der Kunde diesen Unterordner talas:v5_db nicht ändert.
#Füge in deiner .env.local Datei die folgende Zeile hinzu wenn du einen Unterordner verwenden möchtest mit entsprechende Bezeichnung. #Füge in deiner .env.local Datei die folgende Zeile hinzu wenn du einen Unterordner verwenden möchtest mit entsprechende Bezeichnung.
# z.B. http://10.10.0.13/talas5/index.aspx -> NEXT_PUBLIC_BASE_PATH=/talas5 # z.B. http://10.10.0.13/talas5/index.aspx -> basePath in config.json auf /talas5 setzen
# z.B. http://10.10.0.13/xyz/index.aspx -> NEXT_PUBLIC_BASE_PATH=/xyz # z.B. http://10.10.0.13/xyz/index.aspx -> basePath in config.json auf /xyz setzen
NEXT_PUBLIC_BASE_PATH=/talas5 # basePath wird jetzt in public/config.json gepflegt
# Oder leer lassen für direkten Zugriff -> NEXT_PUBLIC_BASE_PATH=
# App-Versionsnummer # App-Versionsnummer
NEXT_PUBLIC_APP_VERSION=1.1.317 NEXT_PUBLIC_APP_VERSION=1.1.318

View File

@@ -20,10 +20,9 @@ NEXT_PUBLIC_USE_MOCKS=false
# Ein Unterordner in der dort hinter liegenden Ordnerstruktur (z.B. http://talasserver/talas5/nodemap/api/talas_v5_DB/ usw.) # Ein Unterordner in der dort hinter liegenden Ordnerstruktur (z.B. http://talasserver/talas5/nodemap/api/talas_v5_DB/ usw.)
# kann bleiben da der Kunde diesen Unterordner talas:v5_db nicht ändert. # kann bleiben da der Kunde diesen Unterordner talas:v5_db nicht ändert.
#Füge in deiner .env.local Datei die folgende Zeile hinzu wenn du einen Unterordner verwenden möchtest mit entsprechende Bezeichnung. #Füge in deiner .env.local Datei die folgende Zeile hinzu wenn du einen Unterordner verwenden möchtest mit entsprechende Bezeichnung.
# z.B. http://10.10.0.13/talas5/index.aspx -> NEXT_PUBLIC_BASE_PATH=/talas5 # z.B. http://10.10.0.13/talas5/index.aspx -> basePath in config.json auf /talas5 setzen
# z.B. http://10.10.0.13/xyz/index.aspx -> NEXT_PUBLIC_BASE_PATH=/xyz # z.B. http://10.10.0.13/xyz/index.aspx -> basePath in config.json auf /xyz setzen
NEXT_PUBLIC_BASE_PATH=/talas5 # basePath wird jetzt in public/config.json gepflegt
# Oder leer lassen für direkten Zugriff -> NEXT_PUBLIC_BASE_PATH=
# App-Versionsnummer # App-Versionsnummer
NEXT_PUBLIC_APP_VERSION=1.1.317 NEXT_PUBLIC_APP_VERSION=1.1.318

View File

@@ -250,7 +250,7 @@ das Objekt selbst
### ♻️ Refactor ### ♻️ Refactor
- Alle hartkodierten `/talas5/`-Pfadangaben entfernt - Alle hartkodierten `/talas5/`-Pfadangaben entfernt
- Dynamischer `basePath` eingeführt über `.env.local → NEXT_PUBLIC_BASE_PATH` - Dynamischer `basePath` eingeführt über `public/config.json → basePath`
- Unterstützt jetzt auch den Betrieb ohne Unterverzeichnis - Unterstützt jetzt auch den Betrieb ohne Unterverzeichnis
### 🧠 Architektur ### 🧠 Architektur

View File

@@ -1,4 +1,11 @@
// config/paths.js // config/paths.js
const basePathRaw = process.env.NEXT_PUBLIC_BASE_PATH || ""; let __configCache;
const BASE_PATH = basePathRaw.replace(/^\/|\/$/g, ""); export async function getBaseUrl() {
export const BASE_URL = BASE_PATH ? `/${BASE_PATH}` : ""; if (__configCache) return __configCache;
const res = await fetch("/config.json");
if (!res.ok) throw new Error("config.json konnte nicht geladen werden");
const config = await res.json();
const basePath = (config.basePath || "").replace(/^\/|\/$/g, "");
__configCache = basePath ? `/${basePath}` : "";
return __configCache;
}

View File

@@ -87,7 +87,7 @@ sequenceDiagram
- **Konfigurierbarer basePath:** - **Konfigurierbarer basePath:**
- **Konfigurierbarer basePath:** - **Konfigurierbarer basePath:**
Pfad wie `/talas5` ist optional und kann per Umgebungsvariable `NEXT_PUBLIC_BASE_PATH` gesetzt Pfad wie `/talas5` ist optional und wird jetzt in `public/config.json` als `basePath` gepflegt
werden. werden.
Die Konfiguration erfolgt je nach Umgebung über: Die Konfiguration erfolgt je nach Umgebung über:

View File

@@ -3,12 +3,12 @@
# 📁 paths.js # 📁 paths.js
Berechnet den sauberen `BASE_URL`-Pfad basierend auf `.env.production` oder Berechnet den sauberen `BASE_URL`-Pfad basierend auf `.env.production` oder
`.env.development → NEXT_PUBLIC_BASE_PATH`. `public/config.json → basePath`.
Entfernt führende und abschließende Slashes. Entfernt führende und abschließende Slashes.
## Beispiel ## Beispiel
Wenn `NEXT_PUBLIC_BASE_PATH = "/talas5/"`, wird `BASE_URL = "/talas5"` gesetzt. Wenn `basePath = "/talas5/"` in config.json gesetzt ist, wird `BASE_URL = "/talas5"` verwendet.
```js ```js
const BASE_PATH = basePathRaw.replace(/^\/|\/$/g, ""); const BASE_PATH = basePathRaw.replace(/^\/|\/$/g, "");

View File

@@ -13,7 +13,7 @@ NodeMap verwendet Umgebungsvariablen zur Steuerung von API-Verhalten, Serverpfad
## 🔧 Wichtige Variablen ## 🔧 Wichtige Variablen
| Variable | Beispielwert | Beschreibung | | Variable | Beispielwert | Beschreibung |
| --------------------------- | ------------------- | --------------------------------------------------------------------- | | --------------------------- | ------------------- | -------------------------------------------------------------------------------------------------------- |
| `DB_HOST` | `localhost` | Adresse des Datenbankservers (MySQL) | | `DB_HOST` | `localhost` | Adresse des Datenbankservers (MySQL) |
| `DB_PORT` | `3306` | Port für die Datenbankverbindung | | `DB_PORT` | `3306` | Port für die Datenbankverbindung |
| `DB_NAME` | `talas` | Datenbankname | | `DB_NAME` | `talas` | Datenbankname |
@@ -21,7 +21,7 @@ NodeMap verwendet Umgebungsvariablen zur Steuerung von API-Verhalten, Serverpfad
| `DB_PASSWORD` | `geheim` | Passwort für MySQL | | `DB_PASSWORD` | `geheim` | Passwort für MySQL |
| `NEXT_PUBLIC_API_PORT_MODE` | `prod` oder `dev` | Steuert API-Routing bei Services (z.B. Portwechsel für lokal) | | `NEXT_PUBLIC_API_PORT_MODE` | `prod` oder `dev` | Steuert API-Routing bei Services (z.B. Portwechsel für lokal) |
| `NEXT_PUBLIC_USE_MOCKS` | `true` oder `false` | Aktiviert den Mockdaten-Modus über `/api/mocks/...` | | `NEXT_PUBLIC_USE_MOCKS` | `true` oder `false` | Aktiviert den Mockdaten-Modus über `/api/mocks/...` |
| `NEXT_PUBLIC_BASE_PATH` | `/talas5` oder leer | Optionaler Pfad, falls App unter Subpfad läuft (z.B. IIS) | | `basePath` (in config.json) | `/talas5` oder leer | Optionaler Pfad, falls App unter Subpfad läuft (z.B. IIS). Wird jetzt in `public/config.json` gepflegt. |
| `NEXT_PUBLIC_DEBUG` | `true` oder `false` | Aktiviert zusätzliche `console.log` Ausgaben für Debugging im Browser | | `NEXT_PUBLIC_DEBUG` | `true` oder `false` | Aktiviert zusätzliche `console.log` Ausgaben für Debugging im Browser |
## 📦 Beispiel `.env.production` ## 📦 Beispiel `.env.production`
@@ -34,7 +34,11 @@ DB_USER=root
DB_PASSWORD=geheim DB_PASSWORD=geheim
NEXT_PUBLIC_API_PORT_MODE=prod NEXT_PUBLIC_API_PORT_MODE=prod
NEXT_PUBLIC_USE_MOCKS=false NEXT_PUBLIC_USE_MOCKS=false
NEXT_PUBLIC_BASE_PATH=/talas5 // public/config.json
{
...
"basePath": "/talas5"
}
NEXT_PUBLIC_DEBUG=false NEXT_PUBLIC_DEBUG=false
``` ```
@@ -48,7 +52,11 @@ DB_USER=root
DB_PASSWORD=geheim DB_PASSWORD=geheim
NEXT_PUBLIC_API_PORT_MODE=dev NEXT_PUBLIC_API_PORT_MODE=dev
NEXT_PUBLIC_USE_MOCKS=true NEXT_PUBLIC_USE_MOCKS=true
NEXT_PUBLIC_BASE_PATH=/talas5 // public/config.json
{
...
"basePath": "/talas5"
}
NEXT_PUBLIC_DEBUG=true NEXT_PUBLIC_DEBUG=true
``` ```

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "nodemap", "name": "nodemap",
"version": "1.1.317", "version": "1.1.318",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "nodemap", "name": "nodemap",
"version": "1.1.317", "version": "1.1.318",
"dependencies": { "dependencies": {
"@emotion/react": "^11.13.3", "@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0", "@emotion/styled": "^11.13.0",

View File

@@ -1,6 +1,6 @@
{ {
"name": "nodemap", "name": "nodemap",
"version": "1.1.317", "version": "1.1.318",
"dependencies": { "dependencies": {
"@emotion/react": "^11.13.3", "@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0", "@emotion/styled": "^11.13.0",

View File

@@ -4,5 +4,6 @@
"local": "http://localhost/talas5/TileMap/mapTiles/{z}/{x}/{y}.png", "local": "http://localhost/talas5/TileMap/mapTiles/{z}/{x}/{y}.png",
"osm": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" "osm": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
}, },
"active": "osm" "active": "osm",
"basePath": "/talas5"
} }

View File

@@ -1,7 +1,17 @@
// /services/webservice/fetchGisLinesStatusService.js // /services/webservice/fetchGisLinesStatusService.js
let __configCache;
async function getConfig() {
if (__configCache) return __configCache;
const res = await fetch("/config.json");
if (!res.ok) throw new Error("config.json konnte nicht geladen werden");
__configCache = await res.json();
return __configCache;
}
export const fetchGisLinesStatusService = async () => { export const fetchGisLinesStatusService = async () => {
const useMocks = process.env.NEXT_PUBLIC_USE_MOCKS === "true"; const useMocks = process.env.NEXT_PUBLIC_USE_MOCKS === "true";
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || ""; const config = await getConfig();
const basePath = config.basePath || "";
if (useMocks) { if (useMocks) {
const mockBasePath = "/api/mocks/webservice/gisLinesStatus"; const mockBasePath = "/api/mocks/webservice/gisLinesStatus";
@@ -16,11 +26,9 @@ export const fetchGisLinesStatusService = async () => {
} }
const mockData = await response.json(); const mockData = await response.json();
if (!Array.isArray(mockData.Statis)) { if (!Array.isArray(mockData.Statis)) {
throw new Error("Ungültige Struktur: 'Status' fehlt im Mock"); throw new Error("Ungültige Struktur: 'Status' fehlt im Mock");
} }
return mockData.Statis; return mockData.Statis;
} else { } else {
const baseUrl = `${window.location.protocol}//${window.location.hostname}:80${basePath}/ClientData/WebServiceMap.asmx`; const baseUrl = `${window.location.protocol}//${window.location.hostname}:80${basePath}/ClientData/WebServiceMap.asmx`;

View File

@@ -1,6 +1,16 @@
let __configCache;
async function getConfig() {
if (__configCache) return __configCache;
const res = await fetch("/config.json");
if (!res.ok) throw new Error("config.json konnte nicht geladen werden");
__configCache = await res.json();
return __configCache;
}
export const fetchGisStationsMeasurementsService = async () => { export const fetchGisStationsMeasurementsService = async () => {
const useMocks = process.env.NEXT_PUBLIC_USE_MOCKS === "true"; const useMocks = process.env.NEXT_PUBLIC_USE_MOCKS === "true";
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || ""; const config = await getConfig();
const basePath = config.basePath || "";
if (useMocks) { if (useMocks) {
const mockBasePath = "/api/mocks/webservice/gisStationsMeasurements"; const mockBasePath = "/api/mocks/webservice/gisStationsMeasurements";

View File

@@ -5,9 +5,19 @@
* @returns {Promise<Array>} Liste mit Points[] * @returns {Promise<Array>} Liste mit Points[]
* @throws {Error} bei Fehler oder ungültiger Antwortstruktur * @throws {Error} bei Fehler oder ungültiger Antwortstruktur
*/ */
let __configCache;
async function getConfig() {
if (__configCache) return __configCache;
const res = await fetch("/config.json");
if (!res.ok) throw new Error("config.json konnte nicht geladen werden");
__configCache = await res.json();
return __configCache;
}
export const fetchGisStationsStaticDistrictService = async () => { export const fetchGisStationsStaticDistrictService = async () => {
const useMocks = process.env.NEXT_PUBLIC_USE_MOCKS === "true"; const useMocks = process.env.NEXT_PUBLIC_USE_MOCKS === "true";
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || ""; const config = await getConfig();
const basePath = config.basePath || "";
if (useMocks) { if (useMocks) {
const mockBasePath = "/api/mocks/webservice/gisStationsStaticDistrict"; const mockBasePath = "/api/mocks/webservice/gisStationsStaticDistrict";

View File

@@ -5,9 +5,19 @@
* @returns {Promise<Array>} Liste mit Statis[] * @returns {Promise<Array>} Liste mit Statis[]
* @throws {Error} bei Fehler oder ungültiger Antwortstruktur * @throws {Error} bei Fehler oder ungültiger Antwortstruktur
*/ */
let __configCache;
async function getConfig() {
if (__configCache) return __configCache;
const res = await fetch("/config.json");
if (!res.ok) throw new Error("config.json konnte nicht geladen werden");
__configCache = await res.json();
return __configCache;
}
export const fetchGisStationsStatusDistrictService = async () => { export const fetchGisStationsStatusDistrictService = async () => {
const useMocks = process.env.NEXT_PUBLIC_USE_MOCKS === "true"; const useMocks = process.env.NEXT_PUBLIC_USE_MOCKS === "true";
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || ""; const config = await getConfig();
const basePath = config.basePath || "";
if (useMocks) { if (useMocks) {
const mockBasePath = "/api/mocks/webservice/gisStationsStatusDistrict"; const mockBasePath = "/api/mocks/webservice/gisStationsStatusDistrict";

View File

@@ -4,9 +4,19 @@
* @returns {Promise<Array>} Liste mit Systems[] * @returns {Promise<Array>} Liste mit Systems[]
* @throws {Error} bei Fehler oder ungültiger Antwortstruktur * @throws {Error} bei Fehler oder ungültiger Antwortstruktur
*/ */
let __configCache;
async function getConfig() {
if (__configCache) return __configCache;
const res = await fetch("/config.json");
if (!res.ok) throw new Error("config.json konnte nicht geladen werden");
__configCache = await res.json();
return __configCache;
}
export const fetchGisSystemStaticService = async () => { export const fetchGisSystemStaticService = async () => {
const useMocks = process.env.NEXT_PUBLIC_USE_MOCKS === "true"; const useMocks = process.env.NEXT_PUBLIC_USE_MOCKS === "true";
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || ""; const config = await getConfig();
const basePath = config.basePath || "";
if (useMocks) { if (useMocks) {
const mockBasePath = "/api/mocks/webservice/gisSystemStatic"; const mockBasePath = "/api/mocks/webservice/gisSystemStatic";

View File

@@ -4,9 +4,19 @@
* @returns {Promise<Array>} Rechte-Array * @returns {Promise<Array>} Rechte-Array
* @throws {Error} bei Lade- oder Strukturfehler * @throws {Error} bei Lade- oder Strukturfehler
*/ */
let __configCache;
async function getConfig() {
if (__configCache) return __configCache;
const res = await fetch("/config.json");
if (!res.ok) throw new Error("config.json konnte nicht geladen werden");
__configCache = await res.json();
return __configCache;
}
export const fetchUserRightsService = async () => { export const fetchUserRightsService = async () => {
const useMocks = process.env.NEXT_PUBLIC_USE_MOCKS === "true"; const useMocks = process.env.NEXT_PUBLIC_USE_MOCKS === "true";
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || ""; const config = await getConfig();
const basePath = config.basePath || "";
if (useMocks) { if (useMocks) {
const mockBasePath = "/api/mocks/webservice/gisSystemStatic"; const mockBasePath = "/api/mocks/webservice/gisSystemStatic";

View File

@@ -35,7 +35,14 @@ export const createAndSetDevices = async (
setMarkersFunction([]); setMarkersFunction([]);
return; return;
} }
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || ""; let basePath = "";
try {
const res = await fetch("/config.json");
if (res.ok) {
const config = await res.json();
basePath = config.basePath || "";
}
} catch (e) {}
try { try {
const state = store.getState(); const state = store.getState();

View File

@@ -1,7 +1,9 @@
// utils/openInNewTab.js // utils/openInNewTab.js
export function openInNewTab(e, target) { export async function openInNewTab(e, target) {
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || ""; const res = await fetch("/config.json");
const config = await res.json();
const basePath = config.basePath || "";
const url = new URL(window.location.origin); const url = new URL(window.location.origin);
const originWithoutPort = `${url.protocol}//${url.hostname}`; // ohne Port! const originWithoutPort = `${url.protocol}//${url.hostname}`; // ohne Port!

View File

@@ -17,7 +17,7 @@ import { updatePolylineCoordinatesThunk } from "../../redux/thunks/database/poly
import { openInNewTab } from "../../utils/openInNewTab"; import { openInNewTab } from "../../utils/openInNewTab";
//-------------------------------------------- //--------------------------------------------
export const setupPolylines = ( export const setupPolylines = async (
map, map,
linePositions, linePositions,
lineColors, lineColors,
@@ -29,7 +29,14 @@ export const setupPolylines = (
polylineVisible polylineVisible
) => { ) => {
const mode = process.env.NEXT_PUBLIC_API_PORT_MODE; const mode = process.env.NEXT_PUBLIC_API_PORT_MODE;
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || ""; let basePath = "";
try {
const res = await fetch("/config.json");
if (res.ok) {
const config = await res.json();
basePath = config.basePath || "";
}
} catch (e) {}
if (!polylineVisible) { if (!polylineVisible) {
//console.warn("Polylines deaktiviert - keine Zeichnung"); //console.warn("Polylines deaktiviert - keine Zeichnung");
return { markers: [], polylines: [] }; return { markers: [], polylines: [] };