93 lines
2.9 KiB
Python
Executable File
93 lines
2.9 KiB
Python
Executable File
#!/usr/bin/env -S uv run
|
|
# auto-upgrade@fastapi-vue-setup - remove this if you modify this file
|
|
"""Run Vite development server for frontend and FastAPI backend with auto-reload."""
|
|
|
|
import argparse
|
|
import asyncio
|
|
import contextlib
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from fastapi_vue import server
|
|
|
|
# Import util.py from scripts/fastapi-vue (not a package, so we adjust sys.path)
|
|
sys.path.insert(0, str(Path(__file__).with_name("fastapi-vue")))
|
|
from devutil import ( # type: ignore
|
|
ProcessGroup,
|
|
check_ports_free,
|
|
logger,
|
|
ready,
|
|
setup_fastapi,
|
|
setup_vite,
|
|
)
|
|
|
|
DEFAULT_VITE_PORT = TEMPLATE_VITE_PORT
|
|
DEFAULT_DEV_PORT = TEMPLATE_DEV_PORT
|
|
|
|
|
|
async def run_devserver(frontend: str, backend: str) -> None:
|
|
reporoot = Path(__file__).parent.parent
|
|
front = reporoot / "frontend"
|
|
if not (front / "package.json").exists():
|
|
logger.warning("Frontend source not found at %s", front)
|
|
raise SystemExit(1)
|
|
|
|
viteurl, npm_install, vite = setup_vite(frontend, DEFAULT_VITE_PORT)
|
|
backurl, module, backend_config = setup_fastapi(
|
|
backend, "MODULE_NAME.APP_MODULE:APP_VAR", DEFAULT_DEV_PORT
|
|
)
|
|
|
|
# Tell the everyone where the frontend and backend are (vite proxy, etc)
|
|
os.environ["FASTAPI_VUE_FRONTEND_URL"] = viteurl
|
|
os.environ["FASTAPI_VUE_BACKEND_URL"] = backurl
|
|
|
|
async with ProcessGroup() as pg:
|
|
npm_i = await pg.spawn(*npm_install, cwd=front)
|
|
await check_ports_free(viteurl, backurl)
|
|
|
|
# Run backend in a thread (server.run is blocking)
|
|
loop = asyncio.get_event_loop()
|
|
loop.run_in_executor(None, lambda: server.run(module, **backend_config))
|
|
|
|
# Wait for both install and backend to be ready
|
|
await pg.wait(npm_i, ready(backurl, path="/api/health?from=devserver.py"))
|
|
|
|
# Start Vite dev server (ProcessGroup waits for any exit, then terminates others)
|
|
await pg.spawn(*vite, cwd=front)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="Run Vite and FastAPI development servers",
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
epilog=HELP_EPILOG,
|
|
)
|
|
parser.add_argument(
|
|
"frontend",
|
|
nargs="?",
|
|
metavar="host:port",
|
|
help=f"Vite frontend endpoint (default: localhost:{DEFAULT_VITE_PORT})",
|
|
)
|
|
parser.add_argument(
|
|
"--backend",
|
|
metavar="host:port",
|
|
help=f"FastAPI backend endpoint (default: localhost:{DEFAULT_DEV_PORT})",
|
|
)
|
|
args = parser.parse_args()
|
|
with contextlib.suppress(KeyboardInterrupt):
|
|
asyncio.run(run_devserver(args.frontend, args.backend))
|
|
|
|
|
|
HELP_EPILOG = """
|
|
scripts/devserver.py # Default ports on localhost
|
|
scripts/devserver.py 3000 # Vite on localhost:3000
|
|
scripts/devserver.py :3000 --backend 8000 # *:3000, localhost:8000
|
|
|
|
JS_RUNTIME environment variable can be used to select the JS runtime
|
|
"""
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|