diff --git a/pynecone/.templates/jinja/web/pages/index.js.jinja2 b/pynecone/.templates/jinja/web/pages/index.js.jinja2 index 01a22f9ae..17686aebe 100644 --- a/pynecone/.templates/jinja/web/pages/index.js.jinja2 +++ b/pynecone/.templates/jinja/web/pages/index.js.jinja2 @@ -5,9 +5,6 @@ {{custom_code}} {% endfor %} -{% for name, url in endpoints.items() %} -const {{name}} = {{url|json_dumps}} -{% endfor %} {% endblock %} {% block export %} @@ -38,7 +35,7 @@ export default function Component() { return; } if (!{{const.socket}}.current) { - connect({{const.socket}}, {{state_name}}, {{state_name|react_setter}}, {{const.result}}, {{const.result|react_setter}}, {{const.router}}, {{const.event_endpoint}}, {{transports}}) + connect({{const.socket}}, {{state_name}}, {{state_name|react_setter}}, {{const.result}}, {{const.result|react_setter}}, {{const.router}}, {{transports}}) } const update = async () => { if ({{const.result}}.{{const.state}} != null){ diff --git a/pynecone/.templates/web/jsconfig.json b/pynecone/.templates/web/jsconfig.json new file mode 100644 index 000000000..36aa1a4dc --- /dev/null +++ b/pynecone/.templates/web/jsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "baseUrl": "." + } +} diff --git a/pynecone/.templates/web/utils/state.js b/pynecone/.templates/web/utils/state.js index 22b080c04..1e382cb83 100644 --- a/pynecone/.templates/web/utils/state.js +++ b/pynecone/.templates/web/utils/state.js @@ -2,9 +2,11 @@ import axios from "axios"; import io from "socket.io-client"; import JSON5 from "json5"; -import config from "../pynecone.json"; +import env from "env.json"; -const UPLOAD = config.uploadUrl; +const PINGURL = env.pingUrl +const EVENTURL = env.eventUrl +const UPLOADURL = env.uploadUrl // Global variable to hold the token. let token; @@ -121,7 +123,7 @@ export const applyEvent = async (event, router, socket) => { */ export const applyRestEvent = async (queue_event, state, setResult) => { if (queue_event.handler == "uploadFiles") { - await uploadFiles(state, setResult, queue_event.name, UPLOAD); + await uploadFiles(state, setResult, queue_event.name); } }; @@ -184,13 +186,12 @@ export const connect = async ( result, setResult, router, - endpoint, transports ) => { // Get backend URL object from the endpoint - const endpoint_url = new URL(endpoint); + const endpoint_url = new URL(EVENTURL); // Create the socket. - socket.current = io(endpoint, { + socket.current = io(EVENTURL, { path: endpoint_url["pathname"], transports: transports, autoUnref: false, @@ -221,7 +222,7 @@ export const connect = async ( * @param handler The handler to use. * @param endpoint The endpoint to upload to. */ -export const uploadFiles = async (state, setResult, handler, endpoint) => { +export const uploadFiles = async (state, setResult, handler) => { const files = state.files; // return if there's no file to upload @@ -244,7 +245,7 @@ export const uploadFiles = async (state, setResult, handler, endpoint) => { } // Send the file to the server. - await axios.post(endpoint, formdata, headers).then((response) => { + await axios.post(UPLOADURL, formdata, headers).then((response) => { // Apply the delta and set the result. const update = response.data; applyDelta(state, update.delta); diff --git a/pynecone/compiler/compiler.py b/pynecone/compiler/compiler.py index 41db1b1a0..fe0ad876e 100644 --- a/pynecone/compiler/compiler.py +++ b/pynecone/compiler/compiler.py @@ -79,9 +79,6 @@ def _compile_page(component: Component, state: Type[State]) -> str: return templates.PAGE.render( imports=imports, custom_codes=component.get_custom_code(), - endpoints={ - constant.name: constant.get_url() for constant in constants.Endpoint - }, initial_state=utils.compile_state(state), state_name=state.get_name(), hooks=component.get_hooks(), diff --git a/pynecone/components/layout/foreach.py b/pynecone/components/layout/foreach.py index 763680761..352929911 100644 --- a/pynecone/components/layout/foreach.py +++ b/pynecone/components/layout/foreach.py @@ -1,7 +1,7 @@ """Create a list of components from an iterable.""" from __future__ import annotations -from typing import Any, Callable, Dict, List, Set, Tuple, Union +from typing import Any, Callable, Iterable from pynecone.components.component import Component from pynecone.components.layout.fragment import Fragment @@ -13,15 +13,13 @@ class Foreach(Component): """A component that takes in an iterable and a render function and renders a list of components.""" # The iterable to create components from. - iterable: Var[Union[List, Dict, Tuple, Set]] + iterable: Var[Iterable] # A function from the render args to the component. render_fn: Callable = Fragment.create @classmethod - def create( - cls, iterable: Var[Union[List, Dict, Tuple, Set]], render_fn: Callable, **props - ) -> Foreach: + def create(cls, iterable: Var[Iterable], render_fn: Callable, **props) -> Foreach: """Create a foreach component. Args: diff --git a/pynecone/constants.py b/pynecone/constants.py index c916eed6d..e5aecba8e 100644 --- a/pynecone/constants.py +++ b/pynecone/constants.py @@ -58,7 +58,7 @@ NODE_MODULES = "node_modules" PACKAGE_LOCK = "package-lock.json" # The pcversion app file. PCVERSION_APP_FILE = os.path.join(WEB_DIR, "pynecone.json") - +ENV_JSON = os.path.join(WEB_DIR, "env.json") # Commands to run the app. # The frontend default port. diff --git a/pynecone/utils/build.py b/pynecone/utils/build.py index 477e5624d..81b79ee23 100644 --- a/pynecone/utils/build.py +++ b/pynecone/utils/build.py @@ -7,10 +7,7 @@ import os import random import subprocess from pathlib import Path -from typing import ( - TYPE_CHECKING, - Optional, -) +from typing import TYPE_CHECKING, Optional, Union from rich.progress import Progress @@ -22,32 +19,42 @@ if TYPE_CHECKING: from pynecone.app import App -def update_json_file(file_path, key, value): +def update_json_file(file_path: str, update_dict: dict[str, Union[int, str]]): """Update the contents of a json file. Args: file_path: the path to the JSON file. - key: object key to update. - value: value of key. + update_dict: object to update json. """ - with open(file_path) as f: # type: ignore - json_object = json.load(f) - json_object[key] = value - with open(file_path, "w") as f: + fp = Path(file_path) + # create file if it doesn't exist + fp.touch(exist_ok=True) + # create an empty json object if file is empty + fp.write_text("{}") if fp.stat().st_size == 0 else None + + with open(fp) as f: # type: ignore + json_object: dict = json.load(f) + json_object.update(update_dict) + with open(fp, "w") as f: json.dump(json_object, f, ensure_ascii=False) def set_pynecone_project_hash(): """Write the hash of the Pynecone project to a PCVERSION_APP_FILE.""" update_json_file( - constants.PCVERSION_APP_FILE, "project_hash", random.getrandbits(128) + constants.PCVERSION_APP_FILE, {"project_hash": random.getrandbits(128)} ) -def set_pynecone_upload_endpoint(): +def set_environment_variables(): """Write the upload url to a PCVERSION_APP_FILE.""" update_json_file( - constants.PCVERSION_APP_FILE, "uploadUrl", constants.Endpoint.UPLOAD.get_url() + constants.ENV_JSON, + { + "uploadUrl": constants.Endpoint.UPLOAD.get_url(), + "eventUrl": constants.Endpoint.EVENT.get_url(), + "pingUrl": constants.Endpoint.PING.get_url(), + }, ) @@ -195,8 +202,8 @@ def setup_frontend(root: Path, disable_telemetry: bool = True): dest=str(root / constants.WEB_ASSETS_DIR), ) - # set the upload url in pynecone.json file - set_pynecone_upload_endpoint() + # set the environment variables in client(env.json) + set_environment_variables() # Disable the Next telemetry. if disable_telemetry: diff --git a/tests/test_utils.py b/tests/test_utils.py index 181269028..4f5146f08 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -330,7 +330,7 @@ def test_setup_frontend(tmp_path, mocker): assert str(web_folder) == prerequisites.create_web_directory(tmp_path) mocker.patch("pynecone.utils.prerequisites.install_frontend_packages") - mocker.patch("pynecone.utils.build.set_pynecone_upload_endpoint") + mocker.patch("pynecone.utils.build.set_environment_variables") build.setup_frontend(tmp_path, disable_telemetry=False) assert web_folder.exists()