Skip to content

Explicit state and event id minification#6100

Open
benedikt-bartscher wants to merge 60 commits intoreflex-dev:mainfrom
benedikt-bartscher:explicit-event-id-minification
Open

Explicit state and event id minification#6100
benedikt-bartscher wants to merge 60 commits intoreflex-dev:mainfrom
benedikt-bartscher:explicit-event-id-minification

Conversation

@benedikt-bartscher
Copy link
Contributor

@benedikt-bartscher benedikt-bartscher commented Jan 24, 2026

Summary

Add state and event name minification with CLI management tools.

  • Introduces minify.json config file to map state/event names to short IDs (e.g., myapp.state.AppState"a")
  • Adds reflex minify CLI command group for managing minification
  • Reduces frontend bundle size and WebSocket payload size by replacing long state/event paths with compact identifiers

CLI Commands

# Initialize minify.json with IDs for all states and events
reflex minify init

# Sync minify.json after code changes
reflex minify sync
reflex minify sync --prune --reassign-deleted

# Validate config against current codebase
reflex minify validate

# List state tree with minified names
reflex minify list
reflex minify list --json

# Lookup a minified path
reflex minify lookup "a.bU"

based on #6098

@codspeed-hq
Copy link

codspeed-hq bot commented Jan 24, 2026

Merging this PR will improve performance by 3.08%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 1 improved benchmark
✅ 7 untouched benchmarks

Performance Changes

Benchmark BASE HEAD Efficiency
test_compile_stateful[_stateful_page] 154.8 µs 150.2 µs +3.08%

Comparing benedikt-bartscher:explicit-event-id-minification (e8b5724) with main (7607fa3)

Open in CodSpeed

@benedikt-bartscher benedikt-bartscher changed the title Explicit event id minification Explicit state and event id minification Jan 25, 2026
has_substates = len(substates) > 0

if handlers:
console.log(f"{child_prefix}|-- Event Handlers:")
Copy link
Contributor

@abulvenz abulvenz Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very tiny optical nit, cause sometimes EventHandlers is the last sub item.
It might work like this, didn't test it.

Suggested change
console.log(f"{child_prefix}|-- Event Handlers:")
console.log(f"{child_prefix}{'|' if has_substates else '`'}-- Event Handlers:")

@benedikt-bartscher
Copy link
Contributor Author

benedikt-bartscher commented Jan 28, 2026

TODO: best-effort-mode

  • walk trough the state id registry after the app module get's imported
  • filter out all states with explicit state id
  • sort the remaining states without state id by full name
  • assign state ids - start with the highest user defined state id - users might have fragmentation by choice

a similar thing can be implemented for event handler id's

edit: not that easy, as state names are baked into to many things (events, vars etc). we would need to defer init_subclass and possibly parts of @rx.var and @rx.event

edit2: i have found a better approach with a minify.json which makes this obsolete

@benedikt-bartscher
Copy link
Contributor Author

benedikt-bartscher commented Jan 28, 2026

Open for discussion: Should reflex reserve the first 5/10 state id's for internal states? Current reflex uses 0-3, but that might change in the future.

edit: with sibling uniqueness we would just need to reserve the state id's on the first rx.State subclass level.

edit2: i have found a better approach with a minify.json which makes this obsolete

@benedikt-bartscher
Copy link
Contributor Author

benedikt-bartscher commented Jan 28, 2026

TODO: think about sibling uniqueness for states. currently using global uniqueness

edit: adjusted in 6b4c5fa

@benedikt-bartscher benedikt-bartscher force-pushed the explicit-event-id-minification branch from 35ad1c6 to 1647c1e Compare February 1, 2026 10:25
@benedikt-bartscher
Copy link
Contributor Author

Idea: store ids in a minify.json file

  • allows overwriting state ids for upstream dependencies and reflex core
  • one centralized place for the ids
  • keep track of reserved numbers
  • better automatic instrumentation - state and event ids can all be managed with cli - without manual code changes
  • can be loaded once on startup and is frozen - probably faster
  • no best effort mode needed

When a parent and child state have the same minified name, substate
resolution can fail because the leading segment is stripped incorrectly. This
change adds a flag to skip stripping only on the initial recursive call, ensuring
correct resolution even in name collision scenarios.
@benedikt-bartscher
Copy link
Contributor Author

Thanks you @masenf!

the explicit management of the minified names via cli solves our earlier problems of mismatching the minified names between compile and build time, but it seems like a lot of extra api surface area for a mostly under the covers feature.

Yeah, it is. Advanced users and big deployments might prefer managing this manually. I think about it like db migrations. Manual management makes it possible to rename states and event handlers without any issues in production.

would it make sense to auto-minify and store the minify.json as a compilation artifact in the .web/backend directory? we already do something similar to save which pages need to be re-evaluated in backend-only mode in order to have a consistent state tree.

The minify.json should be persisted/commited to have stable id's. However if we decide that minify becomes default, we can certainly auto-update the minify.json during reflex run and/or reflex compile

benedikt-bartscher and others added 27 commits February 13, 2026 20:09
allow newer version of packaging to avoid conflict with hatchling build system
requirements
…6103)

Bumps the uv group with 1 update in the / directory: [python-multipart](https://github.com/Kludex/python-multipart).


Updates `python-multipart` from 0.0.21 to 0.0.22
- [Release notes](https://github.com/Kludex/python-multipart/releases)
- [Changelog](https://github.com/Kludex/python-multipart/blob/master/CHANGELOG.md)
- [Commits](Kludex/python-multipart@0.0.21...0.0.22)

---
updated-dependencies:
- dependency-name: python-multipart
  dependency-version: 0.0.22
  dependency-type: direct:production
  dependency-group: uv
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…andlers (reflex-dev#6099)

* fix: Preserve event_actions from @rx.event decorator in mixin event handlers

* add constant
* Fix socket shape mismatch in queueEvents

Add resolveSocket() helper to handle both ref objects ({ current: Socket })
and raw sockets, fixing a bug where queueEvents would call socket.current
on an already-unwrapped socket, causing processEvent to bail out.

* Address feedback and add JSDoc comment

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
…6097)

* fix: Preserve object identity when pickling MutableProxy

* thanks greptile, it wasn't a dataclass once
…#6082)

* Adding checkbox_visible to rowmarker for data editor

* Update dataeditor.py

* pre-commit

---------

Co-authored-by: Masen Furer <m_github@0x26.net>
* Catch all exceptions in health checks

* log exceptions once in failed health check

avoid spamming the "Database is not initialized, ..." message
This ensures that if the environment path is not correct, we should still be
able to resolve the granian, gunicorn, and uvicorn modules when executing the
server in a subprocess.
…6096)

* Use homogenous tuple annotation in BaseStateMeta.__new__

* update tuple[type, ...] in other places it was used

* precommit
* adding row selection mode

* Update pyi hashes

---------

Co-authored-by: Masen Furer <m_github@0x26.net>
* Update dataeditor.py

* pre commit

---------

Co-authored-by: Masen Furer <m_github@0x26.net>
…eflex-dev#6127)

Bumps the uv group with 1 update in the / directory: [pillow](https://github.com/python-pillow/Pillow).


Updates `pillow` from 12.1.0 to 12.1.1
- [Release notes](https://github.com/python-pillow/Pillow/releases)
- [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst)
- [Commits](python-pillow/Pillow@12.1.0...12.1.1)

---
updated-dependencies:
- dependency-name: pillow
  dependency-version: 12.1.1
  dependency-type: direct:development
  dependency-group: uv
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
User can set GRANIAN_LOG_LEVEL environment variable to override the default
"critical" value.
…erformance (reflex-dev#6118)

* fix: cache get_type_hints for heavy init subclass stuff to improve import performance

* fix: prefer tuple and improve mixin typing
* 0828dev

* does 15 fix this

* ok it seems there are css issues

* is it autoprefixer??

* idk

* wtf is wrong with this

* idk even

* is it granian?

* ok

* vite

* fix types

* bump granian
Certain build environments, such as docker bind mounts, can create symlinks
that exist, but cannot be overwritten for whatever reason. So we unlink those
for Simon 🎁
…x-dev#6147)

* feat: add vite_allowed_hosts config option for Vite dev server

Add a configurable `vite_allowed_hosts` field to `rx.Config` that controls
whether `allowedHosts: true` is set in the Vite dev server configuration.

This allows users running Reflex in Docker, Codespaces, or behind a reverse
proxy to opt-in to allowing all hosts, preventing 403 Forbidden errors from
Vite's host header validation.

Default is `False` (original behavior, Vite only allows localhost).
Users can enable it in rxconfig.py:
  config = rx.Config(app_name="myapp", vite_allowed_hosts=True)
Or via environment variable:
  REFLEX_VITE_ALLOWED_HOSTS=true reflex run

* refactor: support bool | list[str] for vite_allowed_hosts

* feat: support union types in interpret_env_var_value

Instead of raising an error for union types, try each type in the union
in order and return the first successful interpretation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Masen Furer <m_github@0x26.net>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…fallback (reflex-dev#6154)

* fix: include frontend_path in sirv prod command for correct 404.html fallback

When frontend_path is set, the build moves all static files (including
404.html) into a subdirectory, but the sirv --single flag was hardcoded
to look for 404.html at the root. This broke dynamic routes in prod.

Closes reflex-dev#5812

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Update reflex/constants/installer.py

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
…lex-dev#6155)

* fix: make disable_plugins accept Plugin types instead of strings

Change `disable_plugins` from `list[str]` to `list[type[Plugin]]` so both
`plugins` and `disable_plugins` use consistent Plugin-based types (reflex-dev#6150).

Strings and instances are still accepted at runtime with a deprecation
warning, and normalized to the Plugin class. Environment variable support
via REFLEX_DISABLE_PLUGINS continues to work through a new
`interpret_plugin_class_env` interpreter, which `interpret_plugin_env`
now reuses for class resolution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Update reflex/config.py

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…date

sync_minify_config and validate_minify_config grouped siblings by
string-splitting state paths, which fails when children of the same
parent class are defined in different Python modules. This caused
colliding minified IDs (e.g. both getting 'a').

Now uses get_parent_state() class objects for grouping, consistent
with generate_minify_config which was already correct.

Also resolves merge conflicts in _get_event_handler to keep the
minified event name reverse lookup.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants