"""将 Vue 前端构建产物挂载到 FastAPI,实现单端口 Web 访问。""" from pathlib import Path from fastapi import FastAPI, HTTPException from fastapi.responses import FileResponse from fastapi.staticfiles import StaticFiles def mount_frontend(app: FastAPI, static_dir: Path) -> bool: """挂载 frontend/dist。成功返回 True,目录不存在返回 False。""" static_dir = static_dir.resolve() index = static_dir / "index.html" if not index.is_file(): return False assets_dir = static_dir / "assets" if assets_dir.is_dir(): app.mount("/assets", StaticFiles(directory=assets_dir), name="assets") @app.get("/", include_in_schema=False) async def serve_index(): return FileResponse(index) @app.get("/{filename}", include_in_schema=False) async def serve_root_static(filename: str): if filename.startswith("api") or filename in ("docs", "redoc", "openapi.json"): raise HTTPException(status_code=404, detail="Not Found") file_path = (static_dir / filename).resolve() try: file_path.relative_to(static_dir) except ValueError: raise HTTPException(status_code=404, detail="Not Found") if file_path.is_file(): return FileResponse(file_path) return FileResponse(index) return True