Latest Results
feat(compiler): mirror memo output paths to Python source modules (#6457)
* feat(compiler): mirror memo output paths to Python source modules
Memos now compile into a single JSX file per user module at a path that
mirrors the module's dotted name, instead of one file per memo under
. The page-side import surface matches the source
layout, which makes debugging easier and lets Vite group co-defined
memos in the same chunk.
Memos without a captured source module keep the legacy per-name files
and index. A manifest in records emitted
paths so stale files from previous compiles get pruned.
* fix(compiler): strip self-imports in mirrored memo modules + windows path tests
* fix(compiler): scope auto-memo registry by source module
Identical memoizable subtrees on pages from different user modules
produce the same wrapper tag. The auto-memo registry was keyed by tag
alone, so the second registration overwrote the first — only one of
the source modules got a mirrored memo file emitted, and the other
page imported the tag from a JSX file that never declared it. Vite
failed the prod build with MISSING_EXPORT.
Key the registry by (tag, source_module) so each module's mirrored
file gets its own definition, and add an integration test that builds
two pages from distinct user modules sharing a memoizable subtree.
* removed integeration tests. Slow way to prove what already unit tests prove.
* fix(compiler): refresh memo source-module origin to track hot-reloads
was d, so once a
module had been resolved its mirrored path was frozen for the
process. A user toggling a module between a regular and a
package () during dev reload kept the original origin
and emitted memo files to the stale path.
Drop the cache and read from first, falling
back to only when the module isn't loaded —
is rebound on reload, while a cached spec wouldn't be. Also tighten
to close the mkstemp fd up front so it can't
leak if reopening raises, and re-export from
for parity with the rest of the surface.
* test: match memo compile output by content, not per-name path
Memo components now mirror to their source module's combined file, so
the self-referencing memo test can no longer find a per-name
RecursiveBox.jsx path. Join all emitted code and assert on content.
* feat: mirror auto-memoized component output to source module paths
Auto-memoized (rx.memo) components now compile to .web paths mirroring
their defining Python module instead of a shared components.jsx, scoping
the memo registry per module so same-named components no longer collide.
Adds reflex_base.utils.memo_paths to translate source modules into the
mirrored JSX path and $/... specifier.
* Fix tests that were looking for individual file names
* remove reflex.utils.memo_paths shim module
This is net-new functionality, we don't need to provide compat shims
* avoid experiemental namespace in tests
use more durable module/package names that are less likely to change in the future
* remove weird importlib import of reflex.experimental.memo
1. the import was weird, why not just import directly?
2. the canonical location for _get_memo_component_class has moved to reflex_base
* feat: isolate memo output under reserved app_components/ directory
Mirrored memos could compile to paths that overwrite framework output
(a memo in module `app.root` would clobber `.web/app/root.jsx`), and
un-mirrorable memos shared `.web/utils/components`. Move all memo output
under a reserved `app_components/` tree — mirrored memos at
`app_components/<segments>`, un-mirrorable ones at
`app_components/_internal/<name>` — so user module paths can never
collide with framework files.
Add collision detection (reserved internal dir, case-insensitive path
clashes) and reject Windows reserved device names so mirroring fails
loudly instead of silently overwriting. Reset the memo wrapper class
cache each compile so a module flipping to a package across hot reloads
re-resolves its library. Move stale-file pruning after the dry-run
return so `--dry` never mutates `.web` or the manifest.
* fix: prune memo files correctly when .web dir is relative
The is-absolute guard double-prefixed emitted paths to `.web/.web/...`
when get_web_dir() returns the default relative path, so emitted keys
never matched the manifest and live files were wrongly pruned. Emitted
paths already share the web_dir prefix, so strip it directly.
* chore: regenerate memo.pyi stub hash
* refactor: mirror framework memos by real module, drop reserved _internal dir
Framework-defined memos now mirror to their real package name under
app_components/ like any other module, instead of being forced into the
shared fallback. Un-mirrorable memos (__main__, unsafe names) fall back to
the existing utils/components/<name> layout, so the reserved
app_components/_internal/ directory and its collision guard are no longer
needed.
* fix: disambiguate same-named memos across modules by per-module symbol
Two memos sharing a name in different modules mirrored to distinct files
but still exported and imported the same JS identifier, so a page using
both hit a tag collision. Derive a per-module-unique symbol (name plus a
short hash of the dotted module) via the new memo_paths.library_and_symbol,
and route every compiled tag/import/name through it. Key the MEMOS registry
by (name, source_module) so same-named memos in different modules coexist
rather than overwriting each other, while a genuine same-module shadow still
resolves last-wins.
* fix: don't treat reflex_components_* as framework packages
The reflex_components_* prefix is the convention community component
libraries follow, so prefix-matching it as framework wrongly steered
those modules' memos away from their real package name. Match framework
packages by exact name or dot boundary only.
---------
Co-authored-by: Masen Furer <m_github@0x26.net> Latest Branches
0%
carlos/update-book-demo-select-style 0%
0%
masenf/sync-package-json-on-install © 2026 CodSpeed Technology