feat: support embedding Reflex apps into host pages via mount_target#6462
feat: support embedding Reflex apps into host pages via mount_target#6462FarhanAliRaza wants to merge 6 commits intoreflex-dev:mainfrom
Conversation
Add and config options for embedding a Reflex app into an arbitrary DOM node on a host page. When is set, the entry client mounts a memory data router into the target element via instead of hydrating the document, the build emits a stable shim re-exporting the hashed Vite chunk, and a route manifest is generated at compile time so the embedded app owns its own URL space. now sources from the data router's location so the backend sees the in-widget URL rather than the host page's.
Merging this PR will not alter performance
Comparing Footnotes
|
Greptile SummaryThis PR adds
Confidence Score: 4/5The core embedding mechanism is well-reasoned and the happy-path test coverage is solid, but there are error-handling gaps and a caching quirk that could obscure problems in production. All four findings are non-blocking quality concerns: Promise.all lacks error handling so embed mount failures are invisible to users, a misconfigured selector silently triggers document hydration causing cryptic React Router errors on real host pages, @functools.cache contradicts the per-compile-refresh docstring and would serve stale content after a mid-session package upgrade, and the module-level locationRef is null until first render so early events still read the host window.location in embed mode. entry.client.js (error handling and selector fallback behavior) and frontend_skeleton.py (@functools.cache on the template reader) deserve a second look before merge. Important Files Changed
Reviews (1): Last reviewed commit: "feat: support embedding Reflex apps into..." | Re-trigger Greptile |
Split the embed entry into a separate template and only swap it in when mount_target is set, so non-embed builds produce the exact same entry.client.js as before this feature landed.
…e mount Log a clear error when MOUNT_TARGET points at a missing element or the dynamic embed imports reject, instead of silently no-op'ing. Pre-seed locationRef to / in embed mode so events dispatched before the first effect commit don't briefly fall back to the host page's URL. Drop the template read cache so toggling mount_target between compiles picks up the right entry without a re-init.
masenf
left a comment
There was a problem hiding this comment.
My main feedback here is to implement this primarily as a Plugin instead of wiring it through the whole framework. The plugin can take in the mount_target and embed_origin as parameters instead of adding more to the global config.
The only real downside of this approach is the current interpret_plugin_env parser for environment var specified plugins does not expose a way to provide arguments to a plugin class.
|
My thought was plugin too, but most of the will still remain outside of plugin i think. So I implemented this way.. I ll update it. |
Embedding is now opt-in via `rx.plugins.EmbedPlugin(mount_target=...)` in `rx.Config.plugins` rather than top-level `mount_target` / `embed_origin` fields on `BaseConfig`. The plugin owns the embed entry and route-manifest save tasks (no more conditional dispatch in `compile_app`) and gains an optional `dev_preview` mode that injects a Vite middleware serving a minimal host wrapper at `/`, so the embed can be exercised without a separately served host page. `mount_target` / `embed_origin` still fall back to `REFLEX_MOUNT_TARGET` / `REFLEX_EMBED_ORIGIN` so `REFLEX_PLUGINS=...EmbedPlugin` works without constructor args. Compiler and build code now query the active plugin via `get_embed_plugin()` instead of reading config attributes.
Add and config options for embedding a Reflex
app into an arbitrary DOM node on a host page. When is set, the entry client mounts a memory data router into the target element via
instead of hydrating the document, the build emits a stable
shim re-exporting the hashed Vite chunk, and a route
manifest is generated at compile time so the embedded app owns its own URL space. now sources from the data router's
location so the backend sees the in-widget URL rather than the host page's.
Usage
rxconfig.py
usage in the HTML file.
All Submissions:
Type of change
Please delete options that are not relevant.
New Feature Submission:
Changes To Core Features: