From bd0c1621721e4975da5b783c8327701f9823a1dc Mon Sep 17 00:00:00 2001 From: Indiana Date: Mon, 20 Jul 2026 17:48:07 +0000 Subject: [PATCH] feat: serve built frontend from backend with SPA fallback --- backend/app/main.py | 13 +++++++++++++ backend/tests/test_frontend_serving.py | 16 ++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 backend/tests/test_frontend_serving.py diff --git a/backend/app/main.py b/backend/app/main.py index 6f06f28..a41e62e 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -1,11 +1,16 @@ from contextlib import asynccontextmanager +from pathlib import Path from fastapi import FastAPI +from fastapi.responses import FileResponse +from fastapi.staticfiles import StaticFiles import app.models # noqa: F401 — registers models on Base.metadata before create_all from app.db import Base, engine from app.routes.auth import router as auth_router +FRONTEND_DIST = Path(__file__).resolve().parent.parent.parent / "frontend" / "dist" + @asynccontextmanager async def lifespan(app: FastAPI): @@ -21,3 +26,11 @@ app.include_router(auth_router) @app.get("/healthz") async def healthz(): return {"status": "ok"} + + +app.mount("/assets", StaticFiles(directory=FRONTEND_DIST / "assets"), name="frontend-assets") + + +@app.get("/{full_path:path}") +async def serve_spa(full_path: str): + return FileResponse(FRONTEND_DIST / "index.html") diff --git a/backend/tests/test_frontend_serving.py b/backend/tests/test_frontend_serving.py new file mode 100644 index 0000000..4037837 --- /dev/null +++ b/backend/tests/test_frontend_serving.py @@ -0,0 +1,16 @@ +import pytest + + +@pytest.mark.asyncio +async def test_unknown_path_serves_spa_index(client): + response = await client.get("/some/client/side/route") + assert response.status_code == 200 + assert '
' in response.text + + +@pytest.mark.asyncio +async def test_auth_routes_still_work_alongside_spa_fallback(client): + response = await client.post( + "/auth/register", json={"username": "frontendcheck", "password": "spookyspooky"} + ) + assert response.status_code == 201