Upgrade fastapi-vue-setup 1.0.2

This commit is contained in:
2026-02-11 21:33:21 +00:00
parent 97064f7bc7
commit ef7a6c8011
2 changed files with 50 additions and 86 deletions
+32 -43
View File
@@ -1,28 +1,5 @@
#!/usr/bin/env -S uv run
"""Run Vite development server for frontend and Paskia backend with auto-reload.
This script is only available when running from the git repository source,
not from the installed package. It starts both the Vite frontend dev server
and the Paskia backend with auto-reload enabled.
Usage:
uv run scripts/devserver.py [-l host:port] [options...]
The optional -l/--listen argument sets where the Vite frontend listens.
All other options are forwarded to `paskia`.
Backend always listens on localhost:4402.
Environment:
PASKIA_FRONTEND_URL Set by this script for the backend to know where Vite is.
PASKIA_BACKEND_URL Set by this script for Vite to know where to proxy API calls.
PASKIA_SITE_URL User-facing URL for reset links (Caddy HTTPS or Vite HTTP).
Options:
--caddy Run Caddy as HTTPS proxy on port 443 (requires sudo)
--rp-id HOST Relying Party ID (used as hostname for Caddy)
--origin URL Allowed origin(s), passed to backend
--auth-host H Dedicated auth host, passed to backend
"""
"""Run Vite development server for Vue app and FastAPI backend with auto-reload."""
import argparse
import asyncio
@@ -45,26 +22,26 @@ from devutil import ( # noqa: E402
setup_vite,
)
DEFAULT_VITE_PORT = 4403 # overrides by CLI option
BACKEND_PORT = 4402 # hardcoded, also in vite.config.ts
DEFAULT_VITE_PORT = 4403
DEFAULT_DEV_PORT = 4402
CADDY_PORT = 443 # HTTPS port for Caddy proxy
CADDY_HTTP_PORT = 80 # HTTP port for ACME challenges
CADDYFILE_SITE_BLOCK = """\
SITE_ADDR {
# WebSockets bypass directly to backend (workaround for bun proxy bug)
# WebSockets bypass directly to backend (workaround for bun proxy bug)
handle /auth/ws/* {
reverse_proxy localhost:BACKEND_PORT
reverse_proxy BACKEND_ADDR
}
# Everything else goes to or via Vite
handle {
reverse_proxy localhost:VITE_PORT
reverse_proxy VITE_ADDR
}
}
"""
def build_caddyfile(origins: list[str], vite_port: int) -> str:
def build_caddyfile(origins: list[str], viteurl: str, backurl: str) -> str:
"""Build a Caddyfile for the given origins."""
caddyfile_parts = []
for origin in origins:
@@ -78,21 +55,23 @@ def build_caddyfile(origins: list[str], vite_port: int) -> str:
site_addr = f"{scheme}://{host}:{port}"
block = (
CADDYFILE_SITE_BLOCK.replace("SITE_ADDR", site_addr)
.replace("BACKEND_PORT", str(BACKEND_PORT))
.replace("VITE_PORT", str(vite_port))
.replace("BACKEND_ADDR", backurl)
.replace("VITE_ADDR", viteurl)
)
caddyfile_parts.append(block)
return "\n".join(caddyfile_parts)
async def run_caddy(origins: list[str], vite_port: int) -> asyncio.subprocess.Process:
async def run_caddy(
origins: list[str], viteurl: str, backurl: str
) -> asyncio.subprocess.Process:
"""Start Caddy as HTTPS reverse proxy, wait for ready signal."""
caddy_path = shutil.which("caddy")
if not caddy_path:
logger.warning("Caddy not found. Install it to use --caddy option.")
raise SystemExit(1)
caddyfile = build_caddyfile(origins, vite_port)
caddyfile = build_caddyfile(origins, viteurl, backurl)
cmd = ["sudo", caddy_path, "run", "--config", "-", "--adapter", "caddyfile"]
logger.info(">>> sudo caddy @ %s", " ".join(origins))
@@ -163,10 +142,7 @@ async def run_devserver(args: argparse.Namespace, remaining: list[str]) -> None:
raise SystemExit(1)
viteurl, npm_install, vite = setup_vite(args.listen, DEFAULT_VITE_PORT)
backurl, paskia = setup_cli("paskia", f"localhost:{BACKEND_PORT}", BACKEND_PORT)
# Extract vite port for Caddy config
vite_port = int(viteurl.rsplit(":", 1)[1])
backurl, paskia = setup_cli("paskia", args.backend, DEFAULT_DEV_PORT)
# Build paskia command with options
paskia.extend(["--rp-id", args.rp_id])
@@ -197,16 +173,17 @@ async def run_devserver(args: argparse.Namespace, remaining: list[str]) -> None:
caddy_origins = [x for x in caddy_origins if not (x in seen or seen.add(x))]
# Set environment for subprocesses
os.environ["PASKIA_FRONTEND_URL"] = viteurl
os.environ["PASKIA_VITE_URL"] = viteurl
os.environ["PASKIA_BACKEND_URL"] = backurl
os.environ["PASKIA_SITE_URL"] = caddy_origins[0] if args.caddy else viteurl
os.environ["PASKIA_DEV"] = "1"
if args.auth_host:
os.environ["PASKIA_AUTH_HOST"] = args.auth_host
async with ProcessGroup() as pg:
# Start Caddy first if requested (needs to bind ports)
if args.caddy:
caddy_proc = await run_caddy(caddy_origins, vite_port)
caddy_proc = await run_caddy(caddy_origins, viteurl, backurl)
pg._procs.append(caddy_proc)
pg._cmds[caddy_proc.pid] = "caddy"
@@ -222,9 +199,13 @@ def main():
parser.add_argument(
"-l",
"--listen",
metavar="ENDPOINT",
default=None,
help="Vite frontend endpoint (default: localhost:4403)",
metavar="addr",
help=f"Vite (default: localhost:{DEFAULT_VITE_PORT})",
)
parser.add_argument(
"--backend",
metavar="addr",
help=f"FastAPI (default: localhost:{DEFAULT_DEV_PORT})",
)
parser.add_argument("--caddy", action="store_true", help="Run Caddy as HTTPS proxy")
parser.add_argument("--rp-id", default="localhost", help="Relying Party ID")
@@ -238,5 +219,13 @@ def main():
asyncio.run(run_devserver(args, remaining))
HELP_EPILOG = """
Other options are forwarded to paskia [args]
JS_RUNTIME environment variable can be used to select the JS runtime:
npm, deno, bun, or full path to the runtime executable (node maps to npm).
"""
if __name__ == "__main__":
main()