| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- """
- dev.py
- ======
- This script acts as a local development orchestrator.
- It performs three main actions sequentially:
- 1. Executes `roi.py` to fetch the latest market data and generate the frontend JSON files.
- 2. Executes the `bun run build` command to compile the TypeScript frontend into browser-ready JavaScript.
- 3. Spawns a local Python HTTP server pointing to the `www/` directory so you can view the changes in your browser.
- """
- import os # Required for changing working directories and checking paths.
- import subprocess # Required for spawning external processes (like 'bun' and other python scripts).
- import sys # Required to grab the current Python executable path.
- import http.server # Required to run the local web server.
- import socketserver # Required to bind the HTTP handler to a specific port.
- def main() -> None:
- """
- Main execution function for the local development server orchestrator.
- """
- # -------------------------------------------------------------------------
- # STEP 1: GENERATE BACKEND DATA
- # -------------------------------------------------------------------------
- # We first need to ensure that the JSON data files that the frontend consumes
- # actually exist and are up to date. We do this by calling the existing `roi.py` script.
- print(">>> [1/3] Running roi.py to generate updated JSON data...")
- try:
- # sys.executable ensures we use the exact same Python interpreter currently running this script.
- # check=True ensures that if roi.py crashes, this script will also halt and raise a CalledProcessError.
- subprocess.run([sys.executable, "roi.py"], check=True)
- except subprocess.CalledProcessError as e:
- # If roi.py fails, we catch the error, print a helpful message, and exit the program gracefully
- # instead of spitting out a massive unhandled stack trace.
- sys.exit(f"!!! Error: Failed to execute roi.py. Process exited with code {e.returncode}")
- # -------------------------------------------------------------------------
- # STEP 2: BUILD THE FRONTEND
- # -------------------------------------------------------------------------
- # The frontend is written in TypeScript (inside the ts/ folder). Browsers cannot natively
- # execute TypeScript in the way this project is structured. As outlined in `package.json`,
- # 'bun' is used as the bundler to compile these files into the 'www/' directory.
- print(">>> [2/3] Building the TypeScript frontend using Bun...")
- try:
- # We invoke the 'build' script defined in package.json.
- # This corresponds to: "bun build ts/buy.ts ... --outdir www --target browser --sourcemap=external"
- subprocess.run(["bun", "run", "build"], check=True)
- except FileNotFoundError:
- # If 'bun' is not installed or not in the system's PATH, a FileNotFoundError is raised.
- # We must alert the user that this system dependency is missing.
- sys.exit("!!! Error: 'bun' command not found. Please ensure Bun is installed (https://bun.sh/) and in your PATH.")
- except subprocess.CalledProcessError as e:
- # Catch compilation errors in the TypeScript code itself.
- sys.exit(f"!!! Error: Frontend build failed. Bun exited with code {e.returncode}")
- # -------------------------------------------------------------------------
- # STEP 3: SERVE THE FRONTEND LOCALLY
- # -------------------------------------------------------------------------
- # We must serve the compiled files via an HTTP server because opening local HTML files
- # directly (via file:// protocol) often causes CORS (Cross-Origin Resource Sharing) errors
- # when the JavaScript attempts to fetch the local JSON files generated in Step 1.
- print(">>> [3/3] Starting local development server...")
-
- # Define the port we want to host the site on. 8000 is a standard web development port.
- PORT = 8000
- # Define the directory we want to serve. The bun build step outputs to 'www'.
- WEB_DIR = "www"
- # We must ensure the 'www' directory exists before attempting to switch into it.
- if not os.path.isdir(WEB_DIR):
- sys.exit(f"!!! Error: Directory '{WEB_DIR}' does not exist. The build step may have failed silently.")
- # Change the current working directory to 'www'. This ensures the HTTP server roots itself here,
- # making the index.html inside 'www' the default page, and allowing relative path resolutions to work.
- os.chdir(WEB_DIR)
- # http.server.SimpleHTTPRequestHandler is a built-in handler that serves files from the current directory.
- Handler = http.server.SimpleHTTPRequestHandler
- # socketserver.TCPServer creates a TCP server that listens on the specified port and binds our handler to it.
- # We use a 'with' block to ensure the network socket is properly released and cleaned up when the server stops.
- with socketserver.TCPServer(("", PORT), Handler) as httpd:
- print(f">>> Serving at http://localhost:{PORT}")
- print(">>> Press Ctrl+C to stop the server.")
- try:
- # serve_forever() puts the script into an infinite loop, constantly listening for and fulfilling HTTP requests.
- httpd.serve_forever()
- except KeyboardInterrupt:
- # Catch the Ctrl+C command from the user to gracefully shut down the server.
- print("\n>>> Shutting down development server gracefully. Goodbye!")
- if __name__ == '__main__':
- # This standard Python idiom ensures that the main() function is only called if this script
- # is executed directly from the command line (e.g., `python dev.py`), rather than imported as a module.
- main()
|