11
11
from starlette .requests import Request
12
12
from starlette .responses import RedirectResponse
13
13
from starlette .staticfiles import StaticFiles
14
- from starlette .types import Scope
14
+ from starlette .types import Receive , Scope , Send
15
15
from starlette .websockets import WebSocket , WebSocketDisconnect
16
16
17
17
from idom .config import IDOM_WEB_MODULES_DIR
26
26
from idom .core .types import RootComponentConstructor
27
27
28
28
from ._asgi import serve_development_asgi
29
- from .utils import CLIENT_BUILD_DIR
29
+ from .utils import CLIENT_BUILD_DIR , client_build_dir_path
30
30
31
31
32
32
logger = logging .getLogger (__name__ )
@@ -51,9 +51,12 @@ def configure(
51
51
options: Options for configuring server behavior
52
52
"""
53
53
options = options or Options ()
54
- _setup_common_routes (options , app )
54
+
55
+ # this route should take priority so set up it up first
55
56
_setup_single_view_dispatcher_route (options .url_prefix , app , constructor )
56
57
58
+ _setup_common_routes (options , app )
59
+
57
60
58
61
def create_development_app () -> Starlette :
59
62
"""Return a :class:`Starlette` app instance in debug mode"""
@@ -116,39 +119,53 @@ def _setup_common_routes(options: Options, app: Starlette) -> None:
116
119
# This really should be added to the APIRouter, but there's a bug in Starlette
117
120
# BUG: https://github.com/tiangolo/fastapi/issues/1469
118
121
url_prefix = options .url_prefix
122
+
119
123
if options .serve_static_files :
120
- app .mount (
121
- f"{ url_prefix } /client" ,
122
- StaticFiles (
123
- directory = str (CLIENT_BUILD_DIR ),
124
- html = True ,
125
- check_dir = True ,
126
- ),
127
- name = "idom_client_files" ,
128
- )
124
+
125
+ mount_serve_single_page_app_files (app , url_prefix )
126
+
129
127
app .mount (
130
128
f"{ url_prefix } /modules" ,
131
129
StaticFiles (
132
130
directory = str (IDOM_WEB_MODULES_DIR .current ),
133
131
html = True ,
134
132
check_dir = False ,
135
133
),
136
- name = "idom_web_module_files" ,
137
134
)
138
135
139
136
if options .redirect_root :
140
137
141
- @app .route (f" { url_prefix } /" )
138
+ @app .route (url_prefix or " /" )
142
139
def redirect_to_index (request : Request ) -> RedirectResponse :
143
- return RedirectResponse (
144
- f"{ url_prefix } /client/index.html?{ request .query_params } "
145
- )
140
+ redirect_url = url_prefix + "/app"
141
+ if request .query_params :
142
+ redirect_url = f"{ url_prefix } /app?{ request .query_params } "
143
+ else :
144
+ redirect_url = f"{ url_prefix } /app"
145
+ return RedirectResponse (redirect_url )
146
+
147
+
148
+ def mount_serve_single_page_app_files (app : Starlette , url_prefix : str ) -> None :
149
+ asgi_app = StaticFiles (
150
+ directory = CLIENT_BUILD_DIR ,
151
+ html = True ,
152
+ check_dir = False ,
153
+ )
154
+
155
+ async def spa_app (scope : Scope , receive : Receive , send : Send ) -> None :
156
+ return await asgi_app (
157
+ {** scope , "path" : client_build_dir_path (scope ["path" ])},
158
+ receive ,
159
+ send ,
160
+ )
161
+
162
+ app .mount (url_prefix + "/app" , spa_app )
146
163
147
164
148
165
def _setup_single_view_dispatcher_route (
149
166
url_prefix : str , app : Starlette , constructor : RootComponentConstructor
150
167
) -> None :
151
- @app .websocket_route (f" { url_prefix } /stream " )
168
+ @app .websocket_route (url_prefix + "/app{path:path}/_stream " )
152
169
async def model_stream (socket : WebSocket ) -> None :
153
170
await socket .accept ()
154
171
send , recv = _make_send_recv_callbacks (socket )
0 commit comments