feat: production build with FastAPI static file serving for SPA

- Add StaticFiles mount for /assets
- Add catch-all route serving index.html for SPA client routing
- Frontend build: 101KB gzipped total

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
walkpan
2026-03-29 22:05:56 +08:00
parent 5f09c6f144
commit 38766ca792

View File

@@ -1,14 +1,17 @@
import asyncio
import logging
import sys
import pathlib
from contextlib import asynccontextmanager
# Windows compatibility: use SelectorEventLoop for paho-mqtt (add_reader/add_writer)
if sys.platform == "win32":
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
from fastapi import FastAPI
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from mqtt_home.config import get_settings
from mqtt_home.database import init_db, get_session_factory, Base
@@ -87,3 +90,15 @@ async def health():
"status": "ok",
"mqtt_connected": mqtt.is_connected if mqtt else False,
}
# Serve frontend static files in production
_frontend_dist = pathlib.Path(__file__).parent.parent.parent / "frontend" / "dist"
if _frontend_dist.exists():
app.mount("/assets", StaticFiles(directory=str(_frontend_dist / "assets")), name="assets")
@app.get("/{full_path:path}")
async def serve_spa(full_path: str):
file = _frontend_dist / full_path
if file.exists() and file.is_file():
return FileResponse(str(file))
return FileResponse(str(_frontend_dist / "index.html"))