Skip to content

Commit 55527bd

Browse files
committed
get starlette and tornado to work
1 parent 32977ff commit 55527bd

File tree

13 files changed

+4996
-391
lines changed

13 files changed

+4996
-391
lines changed

src/client/package-lock.json

+4,820-343
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/client/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"devDependencies": {
3-
"snowpack": "^3.5.2"
3+
"snowpack": "^3.0.11"
44
},
55
"license": "MIT",
66
"repository": {

src/client/packages/idom-app-react/package-lock.json

+65
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/client/packages/idom-app-react/package.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
"author": "Ryan Morshead",
33
"dependencies": {
44
"idom-client-react": "file:packages/idom-client-react",
5-
"react": "^16.13.1",
6-
"react-dom": "^16.13.1"
5+
"preact": "^10.7.0"
76
},
87
"description": "A client application for IDOM implemented in React",
98
"devDependencies": {

src/client/packages/idom-app-react/src/index.js

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ export function mount(mountPoint) {
44
const serverInfo = new LayoutServerInfo({
55
host: document.location.hostname,
66
port: document.location.port,
7-
path: "../",
87
query: queryParams.user.toString(),
98
secure: document.location.protocol == "https:",
109
});

src/client/packages/idom-client-react/src/server.js

+9-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ export function mountWithLayoutServer(
88
maxReconnectTimeout
99
) {
1010
const loadImportSource = (source, sourceType) =>
11-
import(sourceType == "NAME" ? serverInfo.path.module(source) : source);
11+
import(
12+
sourceType == "NAME" ? serverInfo.path.module(source) : source
13+
).catch(() => {
14+
console.error("Import failed");
15+
});
1216

1317
mountLayoutWithWebSocket(
1418
element,
@@ -18,13 +22,13 @@ export function mountWithLayoutServer(
1822
);
1923
}
2024

21-
export function LayoutServerInfo({ host, port, path, query, secure }) {
25+
export function LayoutServerInfo({ host, port, query, secure }) {
2226
const wsProtocol = "ws" + (secure ? "s" : "");
2327
const httpProtocol = "http" + (secure ? "s" : "");
2428

2529
const uri = host + ":" + port;
26-
path = new URL(path, document.baseURI).pathname;
27-
const url = (uri + path).split("/").slice(0, -1).join("/");
30+
const path = new URL(document.baseURI).pathname;
31+
const url = uri + path;
2832

2933
const wsBaseUrl = wsProtocol + "://" + url;
3034
const httpBaseUrl = httpProtocol + "://" + url;
@@ -36,7 +40,7 @@ export function LayoutServerInfo({ host, port, path, query, secure }) {
3640
}
3741

3842
this.path = {
39-
stream: wsBaseUrl + "/stream" + query,
43+
stream: wsBaseUrl + "/_stream" + query,
4044
module: (source) => httpBaseUrl + `/modules/${source}`,
4145
};
4246
}

src/client/snowpack.config.js

+4
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,8 @@ module.exports = {
44
buildOptions: { out: "../idom/client" },
55
mount: { public: { url: "/", static: true } },
66
optimize: { bundle: true, target: "es2018" },
7+
alias: {
8+
react: "preact/compat",
9+
"react-dom": "preact/compat",
10+
},
711
};

src/idom/server/flask.py

+18-11
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import asyncio
44
import json
55
import logging
6+
import os
67
from asyncio import Queue as AsyncQueue
78
from dataclasses import dataclass
89
from queue import Queue as ThreadQueue
@@ -33,7 +34,7 @@
3334
from idom.core.serve import serve_json_patch
3435
from idom.core.types import ComponentType, RootComponentConstructor
3536

36-
from .utils import CLIENT_BUILD_DIR
37+
from .utils import CLIENT_BUILD_DIR, client_build_dir_path
3738

3839

3940
logger = logging.getLogger(__name__)
@@ -55,14 +56,20 @@ def configure(
5556
"""
5657
options = options or Options()
5758
blueprint = Blueprint("idom", __name__, url_prefix=options.url_prefix)
59+
5860
_setup_common_routes(blueprint, options)
61+
62+
# this route should take priority so set up it up first
5963
_setup_single_view_dispatcher_route(app, options, component)
64+
6065
app.register_blueprint(blueprint)
6166

6267

6368
def create_development_app() -> Flask:
6469
"""Create an application instance for development purposes"""
65-
return Flask(__name__)
70+
os.environ["FLASK_DEBUG"] = "true"
71+
app = Flask(__name__)
72+
return app
6673

6774

6875
async def serve_development_app(
@@ -154,9 +161,13 @@ def _setup_common_routes(blueprint: Blueprint, options: Options) -> None:
154161

155162
if options.serve_static_files:
156163

157-
@blueprint.route("/client/<path:path>")
158-
def send_client_dir(path: str) -> Any:
159-
return send_from_directory(str(CLIENT_BUILD_DIR), path)
164+
@blueprint.route("/app")
165+
@blueprint.route("/app<path:path>")
166+
def send_client_dir(path: str = "") -> Any:
167+
return send_from_directory(
168+
str(CLIENT_BUILD_DIR),
169+
client_build_dir_path(path),
170+
)
160171

161172
@blueprint.route("/modules/<path:path>")
162173
def send_modules_dir(path: str) -> Any:
@@ -167,11 +178,7 @@ def send_modules_dir(path: str) -> Any:
167178
@blueprint.route("/")
168179
def redirect_to_index() -> Any:
169180
return redirect(
170-
url_for(
171-
"idom.send_client_dir",
172-
path="index.html",
173-
**request.args,
174-
)
181+
url_for("idom.send_client_dir", path="", **request.args)
175182
)
176183

177184

@@ -180,7 +187,7 @@ def _setup_single_view_dispatcher_route(
180187
) -> None:
181188
sockets = Sockets(app)
182189

183-
@sockets.route(_join_url_paths(options.url_prefix, "/stream")) # type: ignore
190+
@sockets.route(_join_url_paths(options.url_prefix, "/app<path:path>/_stream")) # type: ignore
184191
def model_stream(ws: WebSocket) -> None:
185192
def send(value: Any) -> None:
186193
ws.send(json.dumps(value))

src/idom/server/sanic.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,12 @@ def configure(
4141
"""Configure an application instance to display the given component"""
4242
options = options or Options()
4343
blueprint = Blueprint(f"idom_dispatcher_{id(app)}", url_prefix=options.url_prefix)
44+
4445
_setup_common_routes(blueprint, options)
46+
47+
# this route should take priority so set up it up first
4548
_setup_single_view_dispatcher_route(blueprint, component)
49+
4650
app.blueprint(blueprint)
4751

4852

@@ -108,7 +112,7 @@ def _setup_common_routes(blueprint: Blueprint, options: Options) -> None:
108112
CORS(blueprint, **cors_params)
109113

110114
if options.serve_static_files:
111-
blueprint.static("/client", str(CLIENT_BUILD_DIR))
115+
blueprint.static("/app", str(CLIENT_BUILD_DIR))
112116
blueprint.static("/modules", str(IDOM_WEB_MODULES_DIR.current))
113117

114118
if options.redirect_root:
@@ -125,7 +129,7 @@ def redirect_to_index(
125129
def _setup_single_view_dispatcher_route(
126130
blueprint: Blueprint, constructor: RootComponentConstructor
127131
) -> None:
128-
@blueprint.websocket("/stream") # type: ignore
132+
@blueprint.websocket("/app<path:path>/_stream") # type: ignore
129133
async def model_stream(
130134
request: request.Request, socket: WebSocketCommonProtocol
131135
) -> None:

src/idom/server/starlette.py

+35-18
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from starlette.requests import Request
1212
from starlette.responses import RedirectResponse
1313
from starlette.staticfiles import StaticFiles
14-
from starlette.types import Scope
14+
from starlette.types import Receive, Scope, Send
1515
from starlette.websockets import WebSocket, WebSocketDisconnect
1616

1717
from idom.config import IDOM_WEB_MODULES_DIR
@@ -26,7 +26,7 @@
2626
from idom.core.types import RootComponentConstructor
2727

2828
from ._asgi import serve_development_asgi
29-
from .utils import CLIENT_BUILD_DIR
29+
from .utils import CLIENT_BUILD_DIR, client_build_dir_path
3030

3131

3232
logger = logging.getLogger(__name__)
@@ -51,9 +51,12 @@ def configure(
5151
options: Options for configuring server behavior
5252
"""
5353
options = options or Options()
54-
_setup_common_routes(options, app)
54+
55+
# this route should take priority so set up it up first
5556
_setup_single_view_dispatcher_route(options.url_prefix, app, constructor)
5657

58+
_setup_common_routes(options, app)
59+
5760

5861
def create_development_app() -> Starlette:
5962
"""Return a :class:`Starlette` app instance in debug mode"""
@@ -116,39 +119,53 @@ def _setup_common_routes(options: Options, app: Starlette) -> None:
116119
# This really should be added to the APIRouter, but there's a bug in Starlette
117120
# BUG: https://github.com/tiangolo/fastapi/issues/1469
118121
url_prefix = options.url_prefix
122+
119123
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+
129127
app.mount(
130128
f"{url_prefix}/modules",
131129
StaticFiles(
132130
directory=str(IDOM_WEB_MODULES_DIR.current),
133131
html=True,
134132
check_dir=False,
135133
),
136-
name="idom_web_module_files",
137134
)
138135

139136
if options.redirect_root:
140137

141-
@app.route(f"{url_prefix}/")
138+
@app.route(url_prefix or "/")
142139
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)
146163

147164

148165
def _setup_single_view_dispatcher_route(
149166
url_prefix: str, app: Starlette, constructor: RootComponentConstructor
150167
) -> None:
151-
@app.websocket_route(f"{url_prefix}/stream")
168+
@app.websocket_route(url_prefix + "/app{path:path}/_stream")
152169
async def model_stream(socket: WebSocket) -> None:
153170
await socket.accept()
154171
send, recv = _make_send_recv_callbacks(socket)

0 commit comments

Comments
 (0)