reactpy
reactpy copied to clipboard
Add a template tag
By submitting this pull request you agree that all contributions to this project are made under the MIT license.
Issues
- fix #653
Summary
Adds template tag support for all of our supported backends.
Checklist
- [ ] Tests have been included for all bug fixes or added functionality.
- [ ] The
changelog.rsthas been updated with any significant changes.
@rmorshea this PR contains the template tag itself, but not in a usable form due to
- ~~Needing modification to websocket URL patterns (new pattern:
reactpy-ws-url/<uuid>?<kwargs>)~~ - Missing JavaScript mount function
- Missing support for Tornado, which does not use Jinja
- Needs proper definitions for the constant vars in
templatetag.py - Needs to verify if components have already been registered
I don't know if I'm going to have time to work on this in-between working on the docs, so feel free to commit directly to this branch if you feel like moving it forward.
This might make more sense as a standalone reactpy-jinja package. It also shouldn't require any modification to the current server API. In short, this will require a system similar to Django's in which you registry views and have a single root view that knows how to route requests to the appropriate component.
The current server API accepts WS connections at _reactp/stream/<path:path>. As such, all you need to do is render views based on the path. That might (very roughly) look something like this:
import json
from urllib.parse import parse_qs, unquote
views: dict[str, Callable[[], Component]] = { ... }
@component
def app():
loc = use_location()
cmpt = views[loc.pathname]
search = json.loads(parse_qs(loc.search[1:])
args = json.loads(unquote(search.get("args", ["[]"])[0]))
kwargs = json.loads(unquote(search.get("kwargs", ["{}"])[0]))
return cmpt(*args, **kwargs)
So in the rough pseudo code above, connecting to a WS at:
_reactpy/stream/my_component?kwargs=%7B%22hello%22%3A%20%22world%22%7D
would effectively render views["my_component"](hello="world").
One could imagine user's interacting with this library in the following way:
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
from reactpy.backend.fastapi import configure
import reactpy_jinja
@reactpy_jinja.register
def my_component(hello):
...
app = FastAPI()
@app.get("/", response_class=HTMLResponse)
async def index(request):
return templates.TemplateResponse("index.html")
configure(app, reactpy_jinja.root)
Where index.html uses the component tag somewhere:
{% component "my_component" hello="world" %}
You think reactpy-jinja could be a good candidate to be contained in the monorepo?
Maybe we should call it reactpy-template-tag to allow for future expansion?
The decorator might be finnicky. Unlike ASGI views, users might not have all of their component functions imported into their main file. We should probably require a template_dirs: list[Glob] for us to automatically parse components from the available HTML templates.
Also do we even want to consider anything unique for Tornado, or do we force Tornado users to install jinja? I'm leaning towards the latter.
I think we really should push for the template tag being built-in to ReactPy. In my opinion, it should be our main way of advertising how to use ReactPy.
I think this work might be easier once we've consolidated around ASGI/WSGI implementations since it can build upon a more uniform application interface.
Yep, that's why this issue is marked as blocked for now.