diff --git a/pynecone/pc.py b/pynecone/pc.py index ca97a15a7..d948f724f 100644 --- a/pynecone/pc.py +++ b/pynecone/pc.py @@ -129,26 +129,36 @@ def run( prerequisites.check_admin_settings() # Get the frontend and backend commands, based on the environment. - frontend_cmd = backend_cmd = None + setup_frontend = frontend_cmd = backend_cmd = None if env == constants.Env.DEV: - frontend_cmd, backend_cmd = exec.run_frontend, exec.run_backend + setup_frontend, frontend_cmd, backend_cmd = ( + build.setup_frontend, + exec.run_frontend, + exec.run_backend, + ) if env == constants.Env.PROD: - frontend_cmd, backend_cmd = exec.run_frontend_prod, exec.run_backend_prod - assert frontend_cmd and backend_cmd, "Invalid env" + setup_frontend, frontend_cmd, backend_cmd = ( + build.setup_frontend_prod, + exec.run_frontend_prod, + exec.run_backend_prod, + ) + assert setup_frontend and frontend_cmd and backend_cmd, "Invalid env" # Post a telemetry event. telemetry.send(f"run-{env.value}", get_config().telemetry_enabled) # Run the frontend and backend. + if frontend: + setup_frontend(Path.cwd(), loglevel) + threading.Thread( + target=frontend_cmd, args=(Path.cwd(), frontend_port, loglevel) + ).start() if backend: + build.setup_backend() threading.Thread( target=backend_cmd, args=(app.__name__, backend_host, backend_port, loglevel), ).start() - if frontend: - threading.Thread( - target=frontend_cmd, args=(app.app, Path.cwd(), frontend_port) - ).start() @cli.command() @@ -217,9 +227,7 @@ def export( if frontend: build.setup_frontend(Path.cwd()) - app = prerequisites.get_app().app build.export_app( - app, backend=backend, frontend=frontend, zip=zipping, diff --git a/pynecone/utils/build.py b/pynecone/utils/build.py index 3562857c7..1e79edb02 100644 --- a/pynecone/utils/build.py +++ b/pynecone/utils/build.py @@ -7,7 +7,7 @@ import os import random import subprocess from pathlib import Path -from typing import TYPE_CHECKING, Optional, Union +from typing import Optional, Union from rich.progress import Progress @@ -15,9 +15,6 @@ from pynecone import constants from pynecone.config import get_config from pynecone.utils import path_ops, prerequisites -if TYPE_CHECKING: - from pynecone.app import App - def update_json_file(file_path: str, update_dict: dict[str, Union[int, str]]): """Update the contents of a json file. @@ -91,7 +88,6 @@ def generate_sitemap(deploy_url: str): def export_app( - app: App, backend: bool = True, frontend: bool = True, zip: bool = False, @@ -101,7 +97,6 @@ def export_app( """Zip up the app for deployment. Args: - app: The app. backend: Whether to zip up the backend app. frontend: Whether to zip up the frontend app. zip: Whether to zip the app. @@ -121,37 +116,34 @@ def export_app( # Add a single task to the progress object task = progress.add_task("Building app... ", total=500) - # Start the progress bar - with progress: - # Run the subprocess command - export_process = subprocess.Popen( - [prerequisites.get_package_manager(), "run", "export"], - cwd=constants.WEB_DIR, - env=os.environ, - stderr=subprocess.STDOUT, - stdout=subprocess.PIPE, # Redirect stdout to a pipe - universal_newlines=True, # Set universal_newlines to True for text mode - ) + # Start the subprocess with the progress bar. + with progress, subprocess.Popen( + [prerequisites.get_package_manager(), "run", "export"], + cwd=constants.WEB_DIR, + env=os.environ, + stderr=subprocess.STDOUT, + stdout=subprocess.PIPE, # Redirect stdout to a pipe + universal_newlines=True, # Set universal_newlines to True for text mode + ) as export_process: + assert export_process.stdout is not None, "No stdout for export process." + for line in export_process.stdout: + # Print the line in debug mode. + if loglevel == constants.LogLevel.DEBUG: + print(line, end="") - if export_process.stdout: - for line in iter(export_process.stdout.readline, ""): - if "Linting and checking " in line: - progress.update(task, advance=100) - elif "Compiled successfully" in line: - progress.update(task, advance=100) - elif "Route (pages)" in line: - progress.update(task, advance=100) - elif "automatically rendered as static HTML" in line: - progress.update(task, advance=100) - elif "Export successful" in line: - print("DOOE") - progress.update(task, completed=500) - break # Exit the loop if the completion message is found - elif loglevel == constants.LogLevel.DEBUG: - print(line, end="") + # Check for special strings and update the progress bar. + if "Linting and checking " in line: + progress.update(task, advance=100) + elif "Compiled successfully" in line: + progress.update(task, advance=100) + elif "Route (pages)" in line: + progress.update(task, advance=100) + elif "automatically rendered as static HTML" in line: + progress.update(task, advance=100) + elif "Export successful" in line: + progress.update(task, completed=500) + break # Exit the loop if the completion message is found - # Wait for the subprocess to complete - export_process.wait() print("Export process completed.") # Zip up the app. @@ -194,13 +186,21 @@ def posix_export(backend: bool = True, frontend: bool = True): os.system(cmd) -def setup_frontend(root: Path, disable_telemetry: bool = True): +def setup_frontend( + root: Path, + loglevel: constants.LogLevel = constants.LogLevel.ERROR, + disable_telemetry: bool = True, +): """Set up the frontend. Args: - root: root path of the project. + root: The root path of the project. + loglevel: The log level to use. disable_telemetry: Whether to disable the Next telemetry. """ + # Validate bun version. + prerequisites.validate_and_install_bun(initialize=False) + # Initialize the web directory if it doesn't exist. web_dir = prerequisites.create_web_directory(root) @@ -233,6 +233,22 @@ def setup_frontend(root: Path, disable_telemetry: bool = True): ) +def setup_frontend_prod( + root: Path, + loglevel: constants.LogLevel = constants.LogLevel.ERROR, + disable_telemetry: bool = True, +): + """Set up the frontend for prod mode. + + Args: + root: The root path of the project. + loglevel: The log level to use. + disable_telemetry: Whether to disable the Next telemetry. + """ + setup_frontend(root, loglevel, disable_telemetry) + export_app(loglevel=loglevel) + + def setup_backend(): """Set up backend. diff --git a/pynecone/utils/exec.py b/pynecone/utils/exec.py index 1fc90b5e5..f05d40f99 100644 --- a/pynecone/utils/exec.py +++ b/pynecone/utils/exec.py @@ -7,19 +7,14 @@ import platform import subprocess from datetime import datetime from pathlib import Path -from typing import TYPE_CHECKING from rich import print from pynecone import constants from pynecone.config import get_config from pynecone.utils import console, prerequisites, processes -from pynecone.utils.build import export_app, setup_backend, setup_frontend from pynecone.utils.watch import AssetFolderWatch -if TYPE_CHECKING: - from pynecone.app import App - def start_watching_assets_folder(root): """Start watching assets folder. @@ -33,14 +28,12 @@ def start_watching_assets_folder(root): def run_process_and_launch_url( run_command: list[str], - root: Path, loglevel: constants.LogLevel = constants.LogLevel.ERROR, ): """Run the process and launch the URL. Args: run_command: The command to run. - root: root path of the project. loglevel: The log level to use. """ process = subprocess.Popen( @@ -72,7 +65,6 @@ def run_process_and_launch_url( def run_frontend( - app: App, root: Path, port: str, loglevel: constants.LogLevel = constants.LogLevel.ERROR, @@ -80,17 +72,10 @@ def run_frontend( """Run the frontend. Args: - app: The app. - root: root path of the project. - port: port of the app. + root: The root path of the project. + port: The port to run the frontend on. loglevel: The log level to use. """ - # validate bun version - prerequisites.validate_and_install_bun(initialize=False) - - # Set up the frontend. - setup_frontend(root) - # Start watching asset folder. start_watching_assets_folder(root) @@ -98,12 +83,11 @@ def run_frontend( console.rule("[bold green]App Running") os.environ["PORT"] = get_config().frontend_port if port is None else port run_process_and_launch_url( - [prerequisites.get_package_manager(), "run", "dev"], root, loglevel + [prerequisites.get_package_manager(), "run", "dev"], loglevel ) def run_frontend_prod( - app: App, root: Path, port: str, loglevel: constants.LogLevel = constants.LogLevel.ERROR, @@ -111,24 +95,17 @@ def run_frontend_prod( """Run the frontend. Args: - app: The app. - root: root path of the project. - port: port of the app. + root: The root path of the project (to keep same API as run_frontend). + port: The port to run the frontend on. loglevel: The log level to use. """ - # Set up the frontend. - setup_frontend(root) - - # Export the app. - export_app(app, loglevel=loglevel) - # Set the port. os.environ["PORT"] = get_config().frontend_port if port is None else port # Run the frontend in production mode. console.rule("[bold green]App Running") run_process_and_launch_url( - [prerequisites.get_package_manager(), "run", "prod"], root, loglevel + [prerequisites.get_package_manager(), "run", "prod"], loglevel ) @@ -146,8 +123,6 @@ def run_backend( port: The app port loglevel: The log level. """ - setup_backend() - cmd = [ "uvicorn", f"{app_name}:{constants.APP_VAR}.{constants.API_VAR}", @@ -181,8 +156,6 @@ def run_backend_prod( port: The app port loglevel: The log level. """ - setup_backend() - num_workers = processes.get_num_workers() command = ( [