Support prod run on windows (#99)

This commit is contained in:
Nikhil Rao 2022-12-14 17:18:20 -08:00 committed by GitHub
parent cf33e86edb
commit 2c3ef6e23f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 65 additions and 55 deletions

View File

@ -220,7 +220,7 @@ We are actively looking for contributors, no matter your skill level or experien
## More Information ## More Information
More information about Pynecone can be found on our website: More information about Pynecone can be found on our website:
- [Pynecone.io](https://pynecone.io) - [pynecone.io](https://pynecone.io)
## License ## License

View File

@ -1,8 +1,9 @@
"""A html component.""" """A html component."""
from typing import Dict
from pynecone.components.layout.box import Box from pynecone.components.layout.box import Box
from pynecone.var import Var from pynecone.var import Var
from typing import Dict
class Html(Box): class Html(Box):
@ -33,7 +34,6 @@ class Html(Box):
if len(children) != 1: if len(children) != 1:
raise ValueError("Must provide children to the html component.") raise ValueError("Must provide children to the html component.")
else: else:
props["dangerouslySetInnerHTML"] = {"__html": children[0]} props["dangerouslySetInnerHTML"] = {"__html": children[0]}
# Create the component. # Create the component.

View File

@ -38,6 +38,8 @@ UTILS_DIR = "utils"
STATE_PATH = os.path.join(UTILS_DIR, "state") STATE_PATH = os.path.join(UTILS_DIR, "state")
# The directory where the app pages are compiled to. # The directory where the app pages are compiled to.
WEB_PAGES_DIR = os.path.join(WEB_DIR, "pages") WEB_PAGES_DIR = os.path.join(WEB_DIR, "pages")
# The directory where the static build is located.
WEB_STATIC_DIR = os.path.join(WEB_DIR, "_static")
# The directory where the utils file is located. # The directory where the utils file is located.
WEB_UTILS_DIR = os.path.join(WEB_DIR, UTILS_DIR) WEB_UTILS_DIR = os.path.join(WEB_DIR, UTILS_DIR)
# The directory where the assets are located. # The directory where the assets are located.

View File

@ -70,9 +70,11 @@ def run(
) )
raise typer.Exit() raise typer.Exit()
# Get the app module.
utils.console.rule("[bold]Starting Pynecone App") utils.console.rule("[bold]Starting Pynecone App")
app = utils.get_app() app = utils.get_app()
# Get the frontend and backend commands, based on the environment.
frontend_cmd = backend_cmd = None frontend_cmd = backend_cmd = None
if env == constants.Env.DEV: if env == constants.Env.DEV:
frontend_cmd, backend_cmd = utils.run_frontend, utils.run_backend frontend_cmd, backend_cmd = utils.run_frontend, utils.run_backend
@ -80,10 +82,11 @@ def run(
frontend_cmd, backend_cmd = utils.run_frontend_prod, utils.run_backend_prod frontend_cmd, backend_cmd = utils.run_frontend_prod, utils.run_backend_prod
assert frontend_cmd and backend_cmd, "Invalid env" assert frontend_cmd and backend_cmd, "Invalid env"
# Run the frontend and backend.
if frontend: if frontend:
frontend_cmd(app) frontend_cmd(app.app)
if backend: if backend:
backend_cmd(app) backend_cmd(app.__name__)
@cli.command() @cli.command()
@ -104,8 +107,8 @@ def deploy(dry_run: bool = False):
# Compile the app in production mode. # Compile the app in production mode.
typer.echo("Compiling production app") typer.echo("Compiling production app")
app = utils.get_app() app = utils.get_app().app
utils.export_app(app) utils.export_app(app, zip=True)
# Exit early if this is a dry run. # Exit early if this is a dry run.
if dry_run: if dry_run:

View File

@ -15,6 +15,7 @@ import subprocess
import sys import sys
from collections import defaultdict from collections import defaultdict
from subprocess import PIPE from subprocess import PIPE
from types import ModuleType
from typing import _GenericAlias # type: ignore from typing import _GenericAlias # type: ignore
from typing import ( from typing import (
TYPE_CHECKING, TYPE_CHECKING,
@ -37,6 +38,7 @@ from pynecone import constants
from pynecone.base import Base from pynecone.base import Base
if TYPE_CHECKING: if TYPE_CHECKING:
from pynecone.app import App
from pynecone.components.component import ImportDict from pynecone.components.component import ImportDict
from pynecone.config import Config from pynecone.config import Config
from pynecone.event import Event, EventHandler, EventSpec from pynecone.event import Event, EventHandler, EventSpec
@ -308,8 +310,8 @@ def get_bun_path() -> str:
return os.path.expandvars(get_config().bun_path) return os.path.expandvars(get_config().bun_path)
def get_app() -> Any: def get_app() -> ModuleType:
"""Get the app based on the default config. """Get the app module based on the default config.
Returns: Returns:
The app based on the default config. The app based on the default config.
@ -372,11 +374,11 @@ def install_bun():
def install_frontend_packages(): def install_frontend_packages():
"""Install the frontend packages.""" """Install the frontend packages."""
# Install the base packages. # Install the base packages.
subprocess.call([get_bun_path(), "install"], cwd=constants.WEB_DIR, stdout=PIPE) subprocess.run([get_bun_path(), "install"], cwd=constants.WEB_DIR, stdout=PIPE)
# Install the app packages. # Install the app packages.
packages = get_config().frontend_packages packages = get_config().frontend_packages
subprocess.call( subprocess.run(
[get_bun_path(), "add", *packages], cwd=constants.WEB_DIR, stdout=PIPE [get_bun_path(), "add", *packages], cwd=constants.WEB_DIR, stdout=PIPE
) )
@ -390,23 +392,30 @@ def is_initialized() -> bool:
return os.path.exists(constants.CONFIG_FILE) and os.path.exists(constants.WEB_DIR) return os.path.exists(constants.CONFIG_FILE) and os.path.exists(constants.WEB_DIR)
def export_app(app): def export_app(app: App, zip: bool = False):
"""Zip up the app for deployment. """Zip up the app for deployment.
Args: Args:
app: The app. app: The app.
zip: Whether to zip the app.
""" """
app.app.compile(force_compile=True) # Force compile the app.
cmd = r"rm -rf .web/_static; cd .web && bun run export && cd _static && zip -r ../../frontend.zip ./* && cd ../.. && zip -r backend.zip ./* -x .web/\* ./assets\* ./frontend.zip\* ./backend.zip\*" app.compile(force_compile=True)
os.system(cmd)
# Remove the static folder.
rm(constants.WEB_STATIC_DIR)
# Export the Next app.
subprocess.run([get_bun_path(), "run", "export"], cwd=constants.WEB_DIR)
# Zip up the app.
if zip:
cmd = r"cd .web/_static && zip -r ../../frontend.zip ./* && cd ../.. && zip -r backend.zip ./* -x .web/\* ./assets\* ./frontend.zip\* ./backend.zip\*"
os.system(cmd)
def setup_frontend(app): def setup_frontend():
"""Set up the frontend. """Set up the frontend."""
Args:
app: The app.
"""
# Initialize the web directory if it doesn't exist. # Initialize the web directory if it doesn't exist.
cp(constants.WEB_TEMPLATE_DIR, constants.WEB_DIR, overwrite=False) cp(constants.WEB_TEMPLATE_DIR, constants.WEB_DIR, overwrite=False)
@ -417,42 +426,38 @@ def setup_frontend(app):
# Link the assets folder. # Link the assets folder.
ln(src=os.path.join("..", constants.APP_ASSETS_DIR), dest=constants.WEB_ASSETS_DIR) ln(src=os.path.join("..", constants.APP_ASSETS_DIR), dest=constants.WEB_ASSETS_DIR)
def run_frontend(app: App):
"""Run the frontend.
Args:
app: The app.
"""
# Set up the frontend.
setup_frontend()
# Compile the frontend. # Compile the frontend.
app.app.compile(force_compile=True) app.compile(force_compile=True)
# Run the frontend in development mode.
def run_frontend(app) -> subprocess.Popen:
"""Run the frontend.
Args:
app: The app.
Returns:
The frontend process.
"""
setup_frontend(app)
command = [get_bun_path(), "run", "dev"]
console.rule("[bold green]App Running") console.rule("[bold green]App Running")
return subprocess.Popen( subprocess.Popen([get_bun_path(), "run", "dev"], cwd=constants.WEB_DIR)
command, cwd=constants.WEB_DIR
) # stdout=PIPE to hide output
def run_frontend_prod(app) -> subprocess.Popen: def run_frontend_prod(app: App):
"""Run the frontend. """Run the frontend.
Args: Args:
app: The app. app: The app.
Returns:
The frontend process.
""" """
setup_frontend(app) # Set up the frontend.
# Export and zip up the frontend and backend then start the frontend in production mode. setup_frontend()
cmd = r"rm -rf .web/_static || true; cd .web && bun run export"
os.system(cmd) # Export the app.
command = [get_bun_path(), "run", "prod"] export_app(app)
return subprocess.Popen(command, cwd=constants.WEB_DIR)
# Run the frontend in production mode.
subprocess.Popen([get_bun_path(), "run", "prod"], cwd=constants.WEB_DIR)
def get_num_workers() -> int: def get_num_workers() -> int:
@ -469,23 +474,23 @@ def get_num_workers() -> int:
return (os.cpu_count() or 1) * 2 + 1 return (os.cpu_count() or 1) * 2 + 1
def run_backend(app): def run_backend(app_name: str):
"""Run the backend. """Run the backend.
Args: Args:
app: The app. app_name: The app name.
""" """
command = constants.RUN_BACKEND + [ command = constants.RUN_BACKEND + [
f"{app.__name__}:{constants.APP_VAR}.{constants.API_VAR}" f"{app_name}:{constants.APP_VAR}.{constants.API_VAR}"
] ]
subprocess.call(command) subprocess.run(command)
def run_backend_prod(app) -> None: def run_backend_prod(app_name: str):
"""Run the backend. """Run the backend.
Args: Args:
app: The app. app_name: The app name.
""" """
num_workers = get_num_workers() num_workers = get_num_workers()
command = constants.RUN_BACKEND_PROD + [ command = constants.RUN_BACKEND_PROD + [
@ -493,9 +498,9 @@ def run_backend_prod(app) -> None:
str(num_workers), str(num_workers),
"--threads", "--threads",
str(num_workers), str(num_workers),
f"{app.__name__}:{constants.APP_VAR}()", f"{app_name}:{constants.APP_VAR}()",
] ]
subprocess.call(command) subprocess.run(command)
def get_production_backend_url() -> str: def get_production_backend_url() -> str: