diff --git a/dashboard/Dockerfile b/dashboard/Dockerfile index f924387..0db1d7e 100644 --- a/dashboard/Dockerfile +++ b/dashboard/Dockerfile @@ -1,52 +1,25 @@ # ========================================== # dashboard/Dockerfile (Production) -# 🔧 OPTIMIERT: Multi-Stage-Build für ein minimales Produktions-Image # ========================================== -# Stage 1: Build-Umgebung FROM node:20-alpine AS build - WORKDIR /app -# Kopiere package.json und pnpm-lock.yaml -COPY package.json package-lock.json ./ +# Kopiere package.json und Lockfile aus dem Build-Kontext (./dashboard) +COPY package*.json ./ -# Installiere pnpm und dann die Abhängigkeiten -# --prod stellt sicher, dass nur Produktions-Abhängigkeiten installiert werden -RUN npm install --frozen-lockfile +# Produktions-Abhängigkeiten installieren +ENV NODE_ENV=production +RUN npm ci --omit=dev -# Kopiere den restlichen Quellcode +# Quellcode kopieren und builden COPY . . - -# Setze Build-Argumente als Umgebungsvariablen ARG VITE_API_URL ENV VITE_API_URL=${VITE_API_URL} - -# Baue die Anwendung für die Produktion RUN npm run build -# Stage 2: Produktions-Umgebung FROM nginx:1.25-alpine - -# Kopiere die gebauten statischen Dateien aus der Build-Stage COPY --from=build /app/dist /usr/share/nginx/html - -# Optional: Eine Nginx-Konfiguration für Single-Page-Applications (SPA) -# Diese leitet alle Anfragen, die keine Dateien sind, auf die index.html um. -# Erstelle eine Datei `nginx.prod.conf` mit folgendem Inhalt: -# server { -# listen 80; -# root /usr/share/nginx/html; -# index index.html; -# location / { -# try_files $uri $uri/ /index.html; -# } -# } -# COPY nginx.prod.conf /etc/nginx/conf.d/default.conf - -# Exponiere Port 80 (Standard-HTTP-Port von Nginx) EXPOSE 80 - -# Starte Nginx -CMD ["nginx", "-g", "daemon off;"] +CMD ["nginx", " -g", "daemon off;"] diff --git a/dashboard/Dockerfile.dev b/dashboard/Dockerfile.dev index ec5c8f3..f607348 100644 --- a/dashboard/Dockerfile.dev +++ b/dashboard/Dockerfile.dev @@ -4,32 +4,25 @@ # ========================================== FROM node:20-alpine -# Setze das Arbeitsverzeichnis auf den Workspace-Root, um die Pfade aus -# docker-compose.override.yml korrekt aufzulösen. -WORKDIR /workspace - -# 🔧 HINZUGEFÜGT: Installiere curl, damit das wait-for-backend.sh Skript funktioniert +# Stelle sicher, dass benötigte Tools verfügbar sind (z. B. für wait-for-backend.sh) RUN apk add --no-cache curl -RUN npm install -g npm - -# Kopiere die package-Dateien in das korrekte Unterverzeichnis. -# Dies nutzt den Docker-Cache: Wenn sich die Dateien nicht ändern, -# wird der `npm install`-Schritt übersprungen. -COPY package.json package-lock.json* ./ - -# Wechsle in das Dashboard-Verzeichnis, um die Befehle auszuführen. +# Setze Arbeitsverzeichnis direkt auf das Dashboard-Verzeichnis im Container +# (Der Build-Kontext ist ./dashboard, siehe docker-compose.override.yml) WORKDIR /workspace/dashboard -# Installiere ALLE Abhängigkeiten (inkl. devDependencies) -RUN npm install +# KOPIEREN: Nur package-Dateien relativ zum Build-Kontext (KEINE /workspace-Pfade) +# package*.json deckt sowohl package.json als auch package-lock.json ab, falls vorhanden +COPY package*.json ./ -# Das Kopieren des restlichen Codes ist nicht nötig, da das gesamte -# Verzeichnis `./:/workspace` in der docker-compose.override.yml gemountet wird. +# Installation robust machen: npm ci erfordert package-lock.json; fallback auf npm install +RUN if [ -f package-lock.json ]; then \ + npm ci --legacy-peer-deps; \ + else \ + npm install --legacy-peer-deps; \ + fi && \ + npm cache clean --force -# Exponiere die Ports für Vite und Node-Debugging -EXPOSE 5173 9229 +EXPOSE 5173 9230 -# Der Startbefehl wird in der docker-compose.override.yml definiert. -# Ein Standard-CMD ist dennoch eine gute Praxis. CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0", "--port", "5173"] diff --git a/dashboard/package-lock.json b/dashboard/package-lock.json index 2a0e13b..d3b97e3 100644 --- a/dashboard/package-lock.json +++ b/dashboard/package-lock.json @@ -8,32 +8,33 @@ "name": "dashboard", "version": "0.0.0", "dependencies": { - "@syncfusion/ej2-base": "^30.2.6", - "@syncfusion/ej2-buttons": "^30.2.4", - "@syncfusion/ej2-calendars": "^30.2.4", - "@syncfusion/ej2-dropdowns": "^30.2.6", - "@syncfusion/ej2-grids": "^30.2.6", - "@syncfusion/ej2-icons": "^30.2.4", - "@syncfusion/ej2-inputs": "^30.2.6", - "@syncfusion/ej2-kanban": "^30.2.4", - "@syncfusion/ej2-layouts": "^30.2.4", - "@syncfusion/ej2-lists": "^30.2.4", - "@syncfusion/ej2-navigations": "^30.2.7", - "@syncfusion/ej2-notifications": "^30.2.4", - "@syncfusion/ej2-popups": "^30.2.4", - "@syncfusion/ej2-react-buttons": "^30.2.4", - "@syncfusion/ej2-react-calendars": "^30.1.37", - "@syncfusion/ej2-react-dropdowns": "^30.1.37", - "@syncfusion/ej2-react-filemanager": "^30.1.38", - "@syncfusion/ej2-react-grids": "^30.1.40", - "@syncfusion/ej2-react-inputs": "^30.1.38", - "@syncfusion/ej2-react-kanban": "^30.1.37", - "@syncfusion/ej2-react-layouts": "^30.1.40", - "@syncfusion/ej2-react-navigations": "^30.2.7", - "@syncfusion/ej2-react-notifications": "^30.1.37", - "@syncfusion/ej2-react-popups": "^30.1.37", - "@syncfusion/ej2-react-schedule": "^30.1.37", - "@syncfusion/ej2-splitbuttons": "^30.2.4", + "@syncfusion/ej2-base": "^30.2.0", + "@syncfusion/ej2-buttons": "^30.2.0", + "@syncfusion/ej2-calendars": "^30.2.0", + "@syncfusion/ej2-dropdowns": "^30.2.0", + "@syncfusion/ej2-grids": "^30.2.0", + "@syncfusion/ej2-icons": "^30.2.0", + "@syncfusion/ej2-inputs": "^30.2.0", + "@syncfusion/ej2-kanban": "^30.2.0", + "@syncfusion/ej2-layouts": "^30.2.0", + "@syncfusion/ej2-lists": "^30.2.0", + "@syncfusion/ej2-navigations": "^30.2.0", + "@syncfusion/ej2-notifications": "^30.2.0", + "@syncfusion/ej2-popups": "^30.2.0", + "@syncfusion/ej2-react-base": "^30.2.0", + "@syncfusion/ej2-react-buttons": "^30.2.0", + "@syncfusion/ej2-react-calendars": "^30.2.0", + "@syncfusion/ej2-react-dropdowns": "^30.2.0", + "@syncfusion/ej2-react-filemanager": "^30.2.0", + "@syncfusion/ej2-react-grids": "^30.2.0", + "@syncfusion/ej2-react-inputs": "^30.2.0", + "@syncfusion/ej2-react-kanban": "^30.2.0", + "@syncfusion/ej2-react-layouts": "^30.2.0", + "@syncfusion/ej2-react-navigations": "^30.2.0", + "@syncfusion/ej2-react-notifications": "^30.2.0", + "@syncfusion/ej2-react-popups": "^30.2.0", + "@syncfusion/ej2-react-schedule": "^30.2.0", + "@syncfusion/ej2-splitbuttons": "^30.2.0", "cldr-data": "^36.0.4", "lucide-react": "^0.522.0", "react": "^19.1.0", diff --git a/dashboard/package.json b/dashboard/package.json index 7695185..a27d02b 100644 --- a/dashboard/package.json +++ b/dashboard/package.json @@ -10,32 +10,33 @@ "preview": "vite preview" }, "dependencies": { - "@syncfusion/ej2-base": "^30.2.6", - "@syncfusion/ej2-buttons": "^30.2.4", - "@syncfusion/ej2-calendars": "^30.2.4", - "@syncfusion/ej2-dropdowns": "^30.2.6", - "@syncfusion/ej2-grids": "^30.2.6", - "@syncfusion/ej2-icons": "^30.2.4", - "@syncfusion/ej2-inputs": "^30.2.6", - "@syncfusion/ej2-kanban": "^30.2.4", - "@syncfusion/ej2-layouts": "^30.2.4", - "@syncfusion/ej2-lists": "^30.2.4", - "@syncfusion/ej2-navigations": "^30.2.7", - "@syncfusion/ej2-notifications": "^30.2.4", - "@syncfusion/ej2-popups": "^30.2.4", - "@syncfusion/ej2-react-buttons": "^30.2.4", - "@syncfusion/ej2-react-calendars": "^30.1.37", - "@syncfusion/ej2-react-dropdowns": "^30.1.37", - "@syncfusion/ej2-react-filemanager": "^30.1.38", - "@syncfusion/ej2-react-grids": "^30.1.40", - "@syncfusion/ej2-react-inputs": "^30.1.38", - "@syncfusion/ej2-react-kanban": "^30.1.37", - "@syncfusion/ej2-react-layouts": "^30.1.40", - "@syncfusion/ej2-react-navigations": "^30.2.7", - "@syncfusion/ej2-react-notifications": "^30.1.37", - "@syncfusion/ej2-react-popups": "^30.1.37", - "@syncfusion/ej2-react-schedule": "^30.1.37", - "@syncfusion/ej2-splitbuttons": "^30.2.4", + "@syncfusion/ej2-base": "^30.2.0", + "@syncfusion/ej2-buttons": "^30.2.0", + "@syncfusion/ej2-calendars": "^30.2.0", + "@syncfusion/ej2-dropdowns": "^30.2.0", + "@syncfusion/ej2-grids": "^30.2.0", + "@syncfusion/ej2-icons": "^30.2.0", + "@syncfusion/ej2-inputs": "^30.2.0", + "@syncfusion/ej2-kanban": "^30.2.0", + "@syncfusion/ej2-layouts": "^30.2.0", + "@syncfusion/ej2-lists": "^30.2.0", + "@syncfusion/ej2-navigations": "^30.2.0", + "@syncfusion/ej2-notifications": "^30.2.0", + "@syncfusion/ej2-popups": "^30.2.0", + "@syncfusion/ej2-react-base": "^30.2.0", + "@syncfusion/ej2-react-buttons": "^30.2.0", + "@syncfusion/ej2-react-calendars": "^30.2.0", + "@syncfusion/ej2-react-dropdowns": "^30.2.0", + "@syncfusion/ej2-react-filemanager": "^30.2.0", + "@syncfusion/ej2-react-grids": "^30.2.0", + "@syncfusion/ej2-react-inputs": "^30.2.0", + "@syncfusion/ej2-react-kanban": "^30.2.0", + "@syncfusion/ej2-react-layouts": "^30.2.0", + "@syncfusion/ej2-react-navigations": "^30.2.0", + "@syncfusion/ej2-react-notifications": "^30.2.0", + "@syncfusion/ej2-react-popups": "^30.2.0", + "@syncfusion/ej2-react-schedule": "^30.2.0", + "@syncfusion/ej2-splitbuttons": "^30.2.0", "cldr-data": "^36.0.4", "lucide-react": "^0.522.0", "react": "^19.1.0", diff --git a/dashboard/vite.config.ts b/dashboard/vite.config.ts index f71b095..57e3533 100644 --- a/dashboard/vite.config.ts +++ b/dashboard/vite.config.ts @@ -1,16 +1,20 @@ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; +// import path from 'path'; // https://vite.dev/config/ export default defineConfig({ plugins: [react()], resolve: { - alias: { - '@syncfusion/ej2-react-navigations': '@syncfusion/ej2-react-navigations/index.js', - '@syncfusion/ej2-react-buttons': '@syncfusion/ej2-react-buttons/index.js', - }, + // 🔧 KORRIGIERT: Entferne die problematischen Aliases komplett + // Diese verursachen das "not an absolute path" Problem + // alias: { + // '@syncfusion/ej2-react-navigations': '@syncfusion/ej2-react-navigations/index.js', + // '@syncfusion/ej2-react-buttons': '@syncfusion/ej2-react-buttons/index.js', + // }, }, optimizeDeps: { + // 🔧 NEU: Force pre-bundling der Syncfusion Module include: [ '@syncfusion/ej2-react-navigations', '@syncfusion/ej2-react-buttons', @@ -19,6 +23,7 @@ export default defineConfig({ '@syncfusion/ej2-buttons', '@syncfusion/ej2-react-base', ], + // 🔧 NEU: Force dependency re-optimization force: true, esbuildOptions: { target: 'es2020', @@ -33,6 +38,7 @@ export default defineConfig({ }, server: { host: '0.0.0.0', + port: 5173, watch: { usePolling: true, }, diff --git a/docker-compose.yml b/docker-compose.yml index 87a3bb9..3e1b4be 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -112,9 +112,8 @@ services: # ✅ GEÄNDERT: Dashboard jetzt mit Node.js/React statt Python/Dash dashboard: build: - context: . - dockerfile: dashboard/Dockerfile - # 🔧 VEREINFACHT: Build-Args werden durch Umgebungsvariablen gesetzt + context: ./dashboard + dockerfile: Dockerfile args: - VITE_API_URL=${API_URL} image: infoscreen-dashboard:latest