Architecture and invariants¶
- The Python CLI bundles only app Python sources and the framework's Python API.
- A small JS bootstrap loads pinned Pyodide and installs those files in its in-memory filesystem. No remote Python execution service is used.
- Decorated Python functions have stable JS React component types. Creating an element calls React.createElement; it never executes the Python component.
- React invokes the JS component wrapper during reconciliation. The wrapper synchronously dispatches to the Python function.
- Python hooks call React's actual dispatcher in that render. React owns scheduling, reconciliation, hook order and state slots.
- React commits DOM operations; Python callbacks receive browser event proxies.
Data and lifetime¶
DOM/JS-component props are native JS values. Python-component props and non-primitive Python state are opaque JS boxes keyed by Python object identity. The Python registry retains objects while their JS boxes are reachable. This avoids serializing every state update and supports dataclasses and other Python objects as state.
Callbacks use a single retained Python dispatcher proxy. JS callback wrappers
and value boxes are weakly cached. JS FinalizationRegistry removes their Python
registry entries after collection. Finalization is nondeterministic; it is not
a substitute for effect unsubscribe/cleanup. Cross-language reference cycles
are a risk requiring continued soak testing. Class adapters detach their JS
owner on unmount. debug_stats() exposes registry sizes for investigation.
Async and Suspense¶
Python coroutines are scheduled on Pyodide's asyncio loop and converted to native
JS promises. Promise holders are necessary: Pyodide otherwise converts a JS
Promise back to a Python Future, losing the identity required by React's use.
Resource caches keep stable holders per key.
A JS render-frame stack preserves original exceptions thrown by React hooks. In particular React's internal suspension sentinel must reach React unchanged; wrapping it as a Python exception breaks Suspense. Ordinary Python render errors remain errors and are handled by React error boundaries.
Server rendering¶
The bundled Node renderer runs the same Python files in Node/Pyodide, with the same React version and bridge, and calls React DOM's server APIs. This permits real hook initialization and matching useId output. It is not an independent Python HTML serializer. The CLI currently starts a new runtime per render. Production serving needs a persistent worker pool, request isolation, caching, timeouts and an HTTP streaming integration.
Concurrency and browser execution¶
React's concurrent scheduler is used. A single synchronous Python component render still occupies the browser main thread until it returns. There is no claim of preempting arbitrary Python computation, using a WebWorker for DOM hooks, or providing parallel CPU execution.
The standard HTML dir attribute and CSS logical properties are available for RTL layouts; this framework does not automatically correct layout or typography.