dev.py 3.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. """
  2. dev.py
  3. ======
  4. This script acts as a local development orchestrator. Instead of recreating the frontend
  5. in Python, which would violate the "Don't Repeat Yourself" (DRY) principle and introduce
  6. massive technical debt, this script leverages the existing architecture.
  7. It performs four main actions sequentially:
  8. 1. Executes `roi.py` to fetch the latest market data and generate the frontend JSON files.
  9. 2. Executes `bun install` to ensure frontend JS dependencies are present.
  10. 3. Executes `bun run build` to compile the TypeScript frontend into browser-ready JavaScript.
  11. 4. Spawns a local Python HTTP server pointing to the `www/` directory.
  12. """
  13. import os # Required for changing working directories and checking paths.
  14. import subprocess # Required for spawning external processes (like 'bun' and other python scripts).
  15. import sys # Required to grab the current Python executable path.
  16. import http.server # Required to run the local web server.
  17. import socketserver # Required to bind the HTTP handler to a specific port.
  18. def main() -> None:
  19. """
  20. Main execution function for the local development server orchestrator.
  21. """
  22. # -------------------------------------------------------------------------
  23. # STEP 1: GENERATE BACKEND DATA
  24. # -------------------------------------------------------------------------
  25. print(">>> [1/4] Running roi.py to generate updated JSON data...")
  26. try:
  27. subprocess.run([sys.executable, "roi.py"], check=True)
  28. except subprocess.CalledProcessError as e:
  29. sys.exit(f"!!! Error: Failed to execute roi.py. Process exited with code {e.returncode}")
  30. # -------------------------------------------------------------------------
  31. # STEP 2: INSTALL FRONTEND DEPENDENCIES
  32. # -------------------------------------------------------------------------
  33. # Unlike 'uv run', 'bun run' does not automatically install missing dependencies
  34. # defined in package.json. We must explicitly invoke 'bun install' first to
  35. # populate the node_modules/ directory.
  36. print(">>> [2/4] Installing frontend dependencies via Bun...")
  37. try:
  38. subprocess.run(["bun", "install"], check=True)
  39. except FileNotFoundError:
  40. # We catch the FileNotFoundError here because this is the first time 'bun' is invoked.
  41. sys.exit("!!! Error: 'bun' command not found. Please ensure Bun is installed (https://bun.sh/) and in your PATH.")
  42. except subprocess.CalledProcessError as e:
  43. sys.exit(f"!!! Error: Frontend dependency installation failed. Bun exited with code {e.returncode}")
  44. # -------------------------------------------------------------------------
  45. # STEP 3: BUILD THE FRONTEND
  46. # -------------------------------------------------------------------------
  47. # Compiles the TypeScript inside ts/ to JavaScript inside www/
  48. print(">>> [3/4] Building the TypeScript frontend using Bun...")
  49. try:
  50. subprocess.run(["bun", "run", "build"], check=True)
  51. except subprocess.CalledProcessError as e:
  52. sys.exit(f"!!! Error: Frontend build failed. Bun exited with code {e.returncode}")
  53. # -------------------------------------------------------------------------
  54. # STEP 4: SERVE THE FRONTEND LOCALLY
  55. # -------------------------------------------------------------------------
  56. print(">>> [4/4] Starting local development server...")
  57. PORT = 8000
  58. WEB_DIR = "www"
  59. if not os.path.isdir(WEB_DIR):
  60. sys.exit(f"!!! Error: Directory '{WEB_DIR}' does not exist. The build step may have failed silently.")
  61. os.chdir(WEB_DIR)
  62. Handler = http.server.SimpleHTTPRequestHandler
  63. with socketserver.TCPServer(("", PORT), Handler) as httpd:
  64. print(f">>> Serving at http://localhost:{PORT}")
  65. print(">>> Press Ctrl+C to stop the server.")
  66. try:
  67. httpd.serve_forever()
  68. except KeyboardInterrupt:
  69. print("\n>>> Shutting down development server gracefully. Goodbye!")
  70. if __name__ == '__main__':
  71. main()