Closed
Description
Current Situation
Currently we perform ASGI routing via backend-specific APIs. However, it is much easier to gain broad compatibility via ASGI middleware. Additionally, we should have a "standalone" mode where ReactPy can run in a production configuration without any backend.
I originally pitched this concept a long time ago during our development of our configure()
function.
Proposed Actions
Create a ReactPy ASGI application and middleware.
Interface Design
# This is "standalone mode"
from reactpy.backend import ReactPy
app = ReactPy(my_component)
# This is "middleware mode"
from reactpy.backend import ReactPy
from sanic import Sanic
app = ReactPy(Sanic())
Implementation Draft
import re
from asgiref.compatibility import guarantee_single_callable
class ReactPy:
def __init__(
self,
application=None,
dispatcher_url="reactpy/stream/${route}${query}",
modules_url="reactpy/modules",
static_url="reactpy/assets",
) -> None:
self.user_app = guarantee_single_callable(application)
self.url_patterns = "|".join((dispatcher_url, modules_url, static_url))
async def __call__(self, scope, receive, send) -> None:
"""The ASGI callable. This determines whether ReactPy should route the the
request to ourselves or to the user application."""
if not self.user_app or re.match(self.url_patterns, scope["path"]):
await self.reactpy_app(scope, receive, send)
else:
await self.user_app(scope, receive, send)
async def reactpy_app(self, scope, send, receive) -> None:
"""The ASGI application for ReactPy."""
# This will handle the following: `index.html` view, component dispatcher, web modules, and static files.