1414from reactpy .utils import vdom_to_html
1515
1616if TYPE_CHECKING :
17+ import uvicorn
1718 from asgiref .typing import ASGIApplication
1819
1920PATH_PREFIX = PurePosixPath ("/_reactpy" )
2021MODULES_PATH = PATH_PREFIX / "modules"
2122ASSETS_PATH = PATH_PREFIX / "assets"
2223STREAM_PATH = PATH_PREFIX / "stream"
23-
2424CLIENT_BUILD_DIR = Path (_reactpy_file_path ).parent / "_static" / "app" / "dist"
2525
26- try :
26+
27+ async def serve_with_uvicorn (
28+ app : ASGIApplication | Any ,
29+ host : str ,
30+ port : int ,
31+ started : asyncio .Event | None ,
32+ ) -> None :
33+ """Run a development server for an ASGI application"""
2734 import uvicorn
28- except ImportError : # nocov
29- pass
30- else :
31-
32- async def serve_development_asgi (
33- app : ASGIApplication | Any ,
34- host : str ,
35- port : int ,
36- started : asyncio .Event | None ,
37- ) -> None :
38- """Run a development server for an ASGI application"""
39- server = uvicorn .Server (
40- uvicorn .Config (
41- app ,
42- host = host ,
43- port = port ,
44- loop = "asyncio" ,
45- reload = True ,
46- )
35+
36+ server = uvicorn .Server (
37+ uvicorn .Config (
38+ app ,
39+ host = host ,
40+ port = port ,
41+ loop = "asyncio" ,
4742 )
48- server .config .setup_event_loop ()
49- coros : list [Awaitable [Any ]] = [server .serve ()]
43+ )
44+ server .config .setup_event_loop ()
45+ coros : list [Awaitable [Any ]] = [server .serve ()]
5046
51- # If a started event is provided, then use it signal based on `server.started`
52- if started :
53- coros .append (_check_if_started (server , started ))
47+ # If a started event is provided, then use it signal based on `server.started`
48+ if started :
49+ coros .append (_check_if_started (server , started ))
5450
55- try :
56- await asyncio .gather (* coros )
57- finally :
58- # Since we aren't using the uvicorn's `run()` API, we can't guarantee uvicorn's
59- # order of operations. So we need to make sure `shutdown()` always has an initialized
60- # list of `self.servers` to use.
61- if not hasattr (server , "servers" ): # nocov
62- server .servers = []
63- await asyncio .wait_for (server .shutdown (), timeout = 3 )
51+ try :
52+ await asyncio .gather (* coros )
53+ finally :
54+ # Since we aren't using the uvicorn's `run()` API, we can't guarantee uvicorn's
55+ # order of operations. So we need to make sure `shutdown()` always has an initialized
56+ # list of `self.servers` to use.
57+ if not hasattr (server , "servers" ): # nocov
58+ server .servers = []
59+ await asyncio .wait_for (server .shutdown (), timeout = 3 )
6460
6561
6662async def _check_if_started (server : uvicorn .Server , started : asyncio .Event ) -> None :
@@ -72,8 +68,7 @@ async def _check_if_started(server: uvicorn.Server, started: asyncio.Event) -> N
7268def safe_client_build_dir_path (path : str ) -> Path :
7369 """Prevent path traversal out of :data:`CLIENT_BUILD_DIR`"""
7470 return traversal_safe_path (
75- CLIENT_BUILD_DIR ,
76- * ("index.html" if path in ("" , "/" ) else path ).split ("/" ),
71+ CLIENT_BUILD_DIR , * ("index.html" if path in {"" , "/" } else path ).split ("/" )
7772 )
7873
7974
@@ -140,6 +135,9 @@ class CommonOptions:
140135 url_prefix : str = ""
141136 """The URL prefix where ReactPy resources will be served from"""
142137
138+ serve_index_route : bool = True
139+ """Automatically generate and serve the index route (``/``)"""
140+
143141 def __post_init__ (self ) -> None :
144142 if self .url_prefix and not self .url_prefix .startswith ("/" ):
145143 msg = "Expected 'url_prefix' to start with '/'"
0 commit comments