# Simple Dockerfile for Hugging Face Spaces # No nginx needed - just serve static files with Python # Stage 1: Build the application FROM node:18-alpine AS builder WORKDIR /app # Install build dependencies RUN apk add --no-cache python3 make g++ # Copy package files COPY package*.json ./ COPY tsconfig*.json ./ COPY vite.config.ts ./ # Install dependencies RUN npm install # Copy source code COPY src/ ./src/ COPY public/ ./public/ COPY index.html ./ # Build the application ENV NODE_ENV=production RUN npm run build # Verify build output RUN ls -la dist/ && echo "✅ Build completed successfully" # Stage 2: Simple Python server for static files FROM python:3.11-slim WORKDIR /app # Copy built app from builder stage COPY --from=builder /app/dist ./ # Create a simple server script RUN echo '#!/usr/bin/env python3\n\ import http.server\n\ import socketserver\n\ import os\n\ import urllib.parse\n\ from pathlib import Path\n\ \n\ class MyHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):\n\ def end_headers(self):\n\ self.send_my_headers()\n\ super().end_headers()\n\ \n\ def send_my_headers(self):\n\ self.send_header("Access-Control-Allow-Origin", "*")\n\ self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")\n\ self.send_header("Access-Control-Allow-Headers", "*")\n\ \n\ def do_GET(self):\n\ # Parse URL to get clean path without query parameters\n\ parsed_url = urllib.parse.urlparse(self.path)\n\ clean_path = parsed_url.path\n\ \n\ # Handle SPA routing - serve index.html for non-file requests\n\ if clean_path != "/" and clean_path != "" and "." not in clean_path:\n\ # Check if this looks like a file path\n\ try:\n\ if clean_path.startswith("/"):\n\ file_path = clean_path[1:]\n\ else:\n\ file_path = clean_path\n\ \n\ # Only check if path is reasonable length and format\n\ if len(file_path) < 200 and not file_path.startswith("?"):\n\ if not Path(file_path).exists():\n\ self.path = "/index.html"\n\ else:\n\ # Very long path or starts with ?, serve index.html\n\ self.path = "/index.html"\n\ except (OSError, ValueError):\n\ # Any error in path checking, serve index.html\n\ self.path = "/index.html"\n\ else:\n\ # Keep original path for actual files\n\ self.path = clean_path\n\ \n\ return super().do_GET()\n\ \n\ def guess_type(self, path):\n\ # Add audio MIME types\n\ if path.endswith(".mp3"):\n\ return "audio/mpeg"\n\ elif path.endswith(".wav"):\n\ return "audio/wav"\n\ elif path.endswith(".ogg"):\n\ return "audio/ogg"\n\ else:\n\ return super().guess_type(path)\n\ \n\ PORT = int(os.environ.get("PORT", 7860))\n\ files = os.listdir(".")\n\ print(f"🚀 Starting server on port {PORT}")\n\ print(f"📁 Serving files from: {os.getcwd()}")\n\ print(f"📋 Files available: {files}")\n\ \n\ with socketserver.TCPServer(("", PORT), MyHTTPRequestHandler) as httpd:\n\ print(f"✅ Server running at http://0.0.0.0:{PORT}")\n\ httpd.serve_forever()\n\ ' > server.py && chmod +x server.py # Expose port 7860 (HF Spaces default) EXPOSE 7860 # Start the server CMD ["python3", "server.py"]