Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
2656ee5
feat: Add explicit state ID minification for states
benedikt-bartscher Jan 24, 2026
1c5114d
drop uploaded_files, don't allow state_id for mixins
benedikt-bartscher Jan 24, 2026
62bf127
Update reflex/state.py
benedikt-bartscher Jan 24, 2026
0858c9e
ruffing
benedikt-bartscher Jan 24, 2026
be13be5
minify event names as well
benedikt-bartscher Jan 24, 2026
e53c76a
wip fixing minifed state names + add cli
benedikt-bartscher Jan 24, 2026
fc4c5e1
wip cli
benedikt-bartscher Jan 25, 2026
6d13bec
wtf prettier
benedikt-bartscher Jan 25, 2026
b2c3f58
Merge remote-tracking branch 'upstream' into explicit-event-id-minifi…
benedikt-bartscher Jan 27, 2026
f2f1ac7
Merge remote-tracking branch 'upstream' into explicit-event-id-minifi…
benedikt-bartscher Jan 28, 2026
db97e3a
update pyi_hashes
benedikt-bartscher Jan 28, 2026
6b4c5fa
unique per sibling
benedikt-bartscher Jan 28, 2026
a230be2
Merge remote-tracking branch 'upstream/main' into explicit-event-id-m…
benedikt-bartscher Feb 1, 2026
1647c1e
fix test state ids
benedikt-bartscher Feb 1, 2026
e375b7e
add best-effort mode for event ids
benedikt-bartscher Feb 1, 2026
a94c98b
minify json poc
benedikt-bartscher Feb 1, 2026
ee4c7f1
fix codespell
benedikt-bartscher Feb 1, 2026
bcc4b49
add support for dynamic event handlers, streamline event handler form…
benedikt-bartscher Feb 1, 2026
fc787e6
forgot to remove this state prefix
benedikt-bartscher Feb 1, 2026
5b6e124
more streamline with format event handler
benedikt-bartscher Feb 1, 2026
ae477ae
allow to enable/disable state and event ID minification independently…
benedikt-bartscher Feb 4, 2026
e13073b
fix: prevent parent-child minified name collision in substate resolution
benedikt-bartscher Feb 4, 2026
d669571
fix: consistent plural naming for state minification env vars
benedikt-bartscher Feb 4, 2026
ed085c0
make integration tests use our typed env helpers
benedikt-bartscher Feb 4, 2026
b2c2ff0
prefer assert isinstance over cast.
benedikt-bartscher Feb 4, 2026
8f44d49
drop old state_id parameter from BaseStateMeta
benedikt-bartscher Feb 4, 2026
cf7b614
fix: drop unused EVENT_ID_MARKER constant
benedikt-bartscher Feb 4, 2026
3074c84
fix: correctly count events in minification cli
benedikt-bartscher Feb 4, 2026
ca73b45
fix: adjust minify lookup cli for new minify.json, add tests
benedikt-bartscher Feb 6, 2026
d5f159c
fix: reflex minify validate - warn and exit 1 if missing entries
benedikt-bartscher Feb 6, 2026
f964c7a
fix: use get_event_handler in upload
benedikt-bartscher Feb 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ reflex.db
node_modules
package-lock.json
*.pyi
.pre-commit-config.yaml
.pre-commit-config.yaml
uploaded_files/*
2 changes: 1 addition & 1 deletion pyi_hashes.json
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@
"reflex/components/react_player/video.pyi": "998671c06103d797c554d9278eb3b2a0",
"reflex/components/react_router/dom.pyi": "3042fa630b7e26a7378fe045d7fbf4af",
"reflex/components/recharts/__init__.pyi": "6ee7f1ca2c0912f389ba6f3251a74d99",
"reflex/components/recharts/cartesian.pyi": "cfca4f880239ffaecdf9fb4c7c8caed5",
"reflex/components/recharts/cartesian.pyi": "642e32b6bb3dd709b2faa726833dc701",
"reflex/components/recharts/charts.pyi": "013036b9c00ad85a570efdb813c1bc40",
"reflex/components/recharts/general.pyi": "d87ff9b85b2a204be01753690df4fb11",
"reflex/components/recharts/polar.pyi": "ad24bd37c6acc0bc9bd4ac01af3ffe49",
Expand Down
19 changes: 10 additions & 9 deletions reflex/.templates/web/utils/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ import {
initialState,
onLoadInternalEvent,
state_name,
exception_state_name,
handle_frontend_exception,
main_state_name,
update_vars_internal,
} from "$/utils/context";
import debounce from "$/utils/helpers/debounce";
import throttle from "$/utils/helpers/throttle";
Expand Down Expand Up @@ -134,7 +136,7 @@ export const isStateful = () => {
if (event_queue.length === 0) {
return false;
}
return event_queue.some((event) => event.name.startsWith("reflex___state"));
return event_queue.some((event) => event.name.startsWith(main_state_name));
};

/**
Expand Down Expand Up @@ -967,7 +969,7 @@ export const useEventLoop = (

window.onerror = function (msg, url, lineNo, columnNo, error) {
addEvents([
ReflexEvent(`${exception_state_name}.handle_frontend_exception`, {
ReflexEvent(handle_frontend_exception, {
info: error.name + ": " + error.message + "\n" + error.stack,
component_stack: "",
}),
Expand All @@ -979,7 +981,7 @@ export const useEventLoop = (
//https://github.com/mknichel/javascript-errors?tab=readme-ov-file#promise-rejection-events
window.onunhandledrejection = function (event) {
addEvents([
ReflexEvent(`${exception_state_name}.handle_frontend_exception`, {
ReflexEvent(handle_frontend_exception, {
info:
event.reason?.name +
": " +
Expand Down Expand Up @@ -1044,10 +1046,9 @@ export const useEventLoop = (
if (storage_to_state_map[e.key]) {
const vars = {};
vars[storage_to_state_map[e.key]] = e.newValue;
const event = ReflexEvent(
`${state_name}.reflex___state____update_vars_internal_state.update_vars_internal`,
{ vars: vars },
);
const event = ReflexEvent(update_vars_internal, {
vars: vars,
});
addEvents([event], e);
}
};
Expand Down Expand Up @@ -1082,7 +1083,7 @@ export const useEventLoop = (
}

// Equivalent to routeChangeStart - runs when navigation begins
const main_state_dispatch = dispatch["reflex___state____state"];
const main_state_dispatch = dispatch[main_state_name];
if (main_state_dispatch !== undefined) {
main_state_dispatch({ is_hydrated_rx_state_: false });
}
Expand Down
21 changes: 8 additions & 13 deletions reflex/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,13 @@
from reflex.event import (
_EVENT_FIELDS,
Event,
EventHandler,
EventSpec,
EventType,
IndividualEventType,
get_hydrate_event,
noop,
)
from reflex.istate.proxy import StateProxy
from reflex.page import DECORATED_PAGES
from reflex.route import (
get_route_args,
Expand Down Expand Up @@ -1619,6 +1619,8 @@ def _process_background(
if not handler.is_background:
return None

substate = StateProxy(substate)

async def _coro():
"""Coroutine to process the event and emit updates inside an asyncio.Task.

Expand Down Expand Up @@ -1934,21 +1936,14 @@ async def upload_file(request: Request):
substate_token = _substate_key(token, handler.rpartition(".")[0])
state = await app.state_manager.get_state(substate_token)

# get the current session ID
# get the current state(parent state/substate)
path = handler.split(".")[:-1]
current_state = state.get_substate(path)
handler_upload_param = ()

# get handler function
func = getattr(type(current_state), handler.split(".")[-1])
_current_state, event_handler = state._get_event_handler(handler)

# check if there exists any handler args with annotation, list[UploadFile]
if isinstance(func, EventHandler):
if func.is_background:
msg = f"@rx.event(background=True) is not supported for upload handler `{handler}`."
raise UploadTypeError(msg)
func = func.fn
if event_handler.is_background:
msg = f"@rx.event(background=True) is not supported for upload handler `{handler}`."
raise UploadTypeError(msg)
func = event_handler.fn
if isinstance(func, functools.partial):
func = func.func
for k, v in get_type_hints(func).items():
Expand Down
36 changes: 31 additions & 5 deletions reflex/compiler/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from reflex import constants
from reflex.constants import Hooks
from reflex.constants.state import CAMEL_CASE_MEMO_MARKER
from reflex.utils.format import format_state_name, json_dumps
from reflex.utils.format import format_event_handler, format_state_name, json_dumps
from reflex.vars.base import VarData

if TYPE_CHECKING:
Expand Down Expand Up @@ -274,6 +274,24 @@ def context_template(
Returns:
Rendered context file content as string.
"""
# Import state classes to get dynamic names (supports minification)
from reflex.state import (
FrontendEventExceptionState,
OnLoadInternalState,
State,
UpdateVarsInternalState,
)

# Compute dynamic state names that respect minification settings
main_state_name = State.get_name()
on_load_internal = format_event_handler(OnLoadInternalState.on_load_internal)
update_vars_internal = format_event_handler(
UpdateVarsInternalState.update_vars_internal
)
handle_frontend_exception = format_event_handler(
FrontendEventExceptionState.handle_frontend_exception
)

initial_state = initial_state or {}
state_contexts_str = "".join([
f"{format_state_name(state_name)}: createContext(null),"
Expand All @@ -284,7 +302,11 @@ def context_template(
rf"""
export const state_name = "{state_name}"

export const exception_state_name = "{constants.CompileVars.FRONTEND_EXCEPTION_STATE_FULL}"
export const main_state_name = "{main_state_name}"

export const update_vars_internal = "{update_vars_internal}"

export const handle_frontend_exception = "{handle_frontend_exception}"

// These events are triggered on initial load and each page navigation.
export const onLoadInternalEvent = () => {{
Expand All @@ -296,15 +318,15 @@ def context_template(
if (client_storage_vars && Object.keys(client_storage_vars).length !== 0) {{
internal_events.push(
ReflexEvent(
'{state_name}.{constants.CompileVars.UPDATE_VARS_INTERNAL}',
'{update_vars_internal}',
{{vars: client_storage_vars}},
),
);
}}

// `on_load_internal` triggers the correct on_load event(s) for the current page.
// If the page does not define any on_load event, this will just set `is_hydrated = true`.
internal_events.push(ReflexEvent('{state_name}.{constants.CompileVars.ON_LOAD_INTERNAL}'));
internal_events.push(ReflexEvent('{on_load_internal}'));

return internal_events;
}}
Expand All @@ -319,7 +341,11 @@ def context_template(
else """
export const state_name = undefined

export const exception_state_name = undefined
export const main_state_name = undefined

export const update_vars_internal = undefined

export const handle_frontend_exception = undefined

export const onLoadInternalEvent = () => []

Expand Down
2 changes: 0 additions & 2 deletions reflex/components/recharts/cartesian.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,10 +242,8 @@ class Brush(Recharts):
end_index: Var[int]

# The fill color of brush
fill: Var[str | Color]

# The stroke color of brush
stroke: Var[str | Color]
Comment on lines -245 to -248
Copy link
Contributor Author

Choose a reason for hiding this comment

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

?


@classmethod
def get_event_triggers(cls) -> dict[str, Var | Any]:
Expand Down
12 changes: 0 additions & 12 deletions reflex/constants/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,6 @@ class CompileVars(SimpleNamespace):
CONNECT_ERROR = "connectErrors"
# The name of the function for converting a dict to an event.
TO_EVENT = "ReflexEvent"
# The name of the internal on_load event.
ON_LOAD_INTERNAL = "reflex___state____on_load_internal_state.on_load_internal"
# The name of the internal event to update generic state vars.
UPDATE_VARS_INTERNAL = (
"reflex___state____update_vars_internal_state.update_vars_internal"
)
# The name of the frontend event exception state
FRONTEND_EXCEPTION_STATE = "reflex___state____frontend_event_exception_state"
# The full name of the frontend exception state
FRONTEND_EXCEPTION_STATE_FULL = (
f"reflex___state____state.{FRONTEND_EXCEPTION_STATE}"
)


class PageNames(SimpleNamespace):
Expand Down
3 changes: 3 additions & 0 deletions reflex/constants/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
from enum import Enum
from types import SimpleNamespace

# The name of the setvar event handler.
SETVAR = "setvar"


class Endpoint(Enum):
"""Endpoints for the reflex backend API."""
Expand Down
13 changes: 13 additions & 0 deletions reflex/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,13 @@ class PathExistsFlag:
ExistingPath = Annotated[Path, PathExistsFlag]


class MinifyMode(enum.Enum):
"""Mode for minification of state/event IDs."""

ENABLED = "enabled"
DISABLED = "disabled"


class PerformanceMode(enum.Enum):
"""Performance mode for the app."""

Expand Down Expand Up @@ -762,6 +769,12 @@ class EnvironmentVariables:
# How long to opportunistically hold the redis lock in milliseconds (must be less than the token expiration).
REFLEX_OPLOCK_HOLD_TIME_MS: EnvVar[int] = env_var(0)

# Whether to enable state ID minification (requires minify.json).
REFLEX_MINIFY_STATES: EnvVar[MinifyMode] = env_var(MinifyMode.DISABLED)

# Whether to enable event ID minification (requires minify.json).
REFLEX_MINIFY_EVENTS: EnvVar[MinifyMode] = env_var(MinifyMode.DISABLED)


environment = EnvironmentVariables()

Expand Down
Loading
Loading