add orjson - #6116
Conversation
Merging this PR will not alter performance
Performance Changes
Comparing Footnotes
|
Greptile SummaryThis PR adds optional
Confidence Score: 5/5This looks safe to merge.
|
| Filename | Overview |
|---|---|
| reflex/app.py | Adds the socket JSON codec and routes event decoding through the shared orjson helper. |
| packages/reflex-components-core/src/reflex_components_core/core/_upload.py | Uses the shared orjson helpers for upload event args and streamed state updates. |
| packages/reflex-base/src/reflex_base/utils/format.py | Adds orjson-backed dump/load helpers, socket-safe serialization, and fallback paths. |
| packages/reflex-base/src/reflex_base/.templates/web/utils/helpers/json.js | Adds frontend JSON parsing that restores non-finite float sentinel values. |
Reviews (21): Last reviewed commit: "useless orjson here" | Re-trigger Greptile
|
the issue with orjson is that we lose NaN handling which is relevant for numpy, which is why we were using JSON5 as well |
|
Yeah, that's why i did not update it in all places |
…llback Happy path uses native JSON.parse; the catch rewrites Python"s bare Infinity/-Infinity/NaN tokens outside string literals before retrying, so only payloads that actually contain specials pay the extra cost. NaN has no JSON literal and becomes null (matches JSON.stringify).
…o null Swap bare NaN for a sentinel string before JSON.parse and revive it back to a real NaN so Python-side float(nan) round-trips to the frontend.
|
related #6339 |
Apply orjson_dumps/orjson_loads helpers to the new reflex_base package locations after upstream's restructuring.
bed6d7b to
7555e7b
Compare
Serialization previously walked every payload with _replace_non_finite_floats before every socket emit to protect NaN/Infinity floats (orjson silently emits null for them) and to escape sentinel-colliding strings. The walk dominated serialization cost (~95% on a 290KB payload) and ran even in the stdlib fallback, making default installs slower than before reflex-dev#6116. Both backends now dump once and decide from the output bytes whether the walk is needed at all: - orjson: None, NaN and Infinity all serialize to exactly the token null, so output without null provably lost no non-finite floats; output without the sentinel prefix has no colliding strings. Only when either substring appears is the payload walked and re-dumped. The default= callback is split into a non-walking pass-1 variant and a walking pass-2 variant so StateUpdate-wrapped payloads keep the fast path. - stdlib (no orjson): bare NaN/Infinity tokens are restored by the frontend's bare-token rewriter, so only a sentinel-prefix hit forces the walk. Restores default-install performance to parity with pre-reflex-dev#6116. Frontend mirror of the same idea: passing a reviver to JSON.parse disables the engine's native fast parser (measured 4-12x slower in Chromium), so parseNonFiniteAwareJSON only applies the reviver when the payload actually contains the sentinel prefix. The upload NDJSON parser gains the bare-token rewriter retry it was missing. Also: hoist the orjson import to module level (was per-call on the compile hot path), make orjson_dumps fall back to stdlib for indent widths other than 2 instead of silently coercing, and preserve kwargs in its TypeError fallback. Serialize-only medians vs stdlib baseline (1000x10 table delta): 1.91ms -> 431us with orjson, parity without. Browser decode of the same delta: 2.05ms -> 506us.
test_process_event_wire measures the full receive -> process -> serialize round trip: raw event JSON decoded via orjson_loads (as socket.io's decoder does), events processed through BaseStateEventProcessor with a real StateManagerMemory, and each delta serialized through orjson_dumps_socket the way App._setup_state wires socket.io's encoder. Parametrized with a small (5-row) and large (500-row) table delta so JSON parse/dump cost is part of the measured path, which no existing benchmark covered.
Serialization previously walked every payload with _replace_non_finite_floats before every socket emit to protect NaN/Infinity floats (orjson silently emits null for them) and to escape sentinel-colliding strings. The walk dominated serialization cost (~95% on a 290KB payload) and ran even in the stdlib fallback, making default installs slower than before reflex-dev#6116. Both backends now dump once and decide from the output bytes whether the walk is needed at all: - orjson: None, NaN and Infinity all serialize to exactly the token null, so output without null provably lost no non-finite floats; output without the sentinel prefix has no colliding strings. Only when either substring appears is the payload walked and re-dumped. The default= callback is split into a non-walking pass-1 variant and a walking pass-2 variant so StateUpdate-wrapped payloads keep the fast path. - stdlib (no orjson): bare NaN/Infinity tokens are restored by the frontend's bare-token rewriter, so only a sentinel-prefix hit forces the walk. Restores default-install performance to parity with pre-reflex-dev#6116. Frontend mirror of the same idea: passing a reviver to JSON.parse disables the engine's native fast parser (measured 4-12x slower in Chromium), so parseNonFiniteAwareJSON only applies the reviver when the payload actually contains the sentinel prefix. The upload NDJSON parser gains the bare-token rewriter retry it was missing. Also: hoist the orjson import to module level (was per-call on the compile hot path), make orjson_dumps fall back to stdlib for indent widths other than 2 instead of silently coercing, and preserve kwargs in its TypeError fallback. Serialize-only medians vs stdlib baseline (1000x10 table delta): 1.91ms -> 431us with orjson, parity without. Browser decode of the same delta: 2.05ms -> 506us.
The stdlib fallbacks (no orjson, or orjson TypeError e.g. >64-bit ints) walked the original packet, but _replace_non_finite_floats cannot traverse custom objects like the StateUpdate every real socket payload wraps. Strings produced by serializers.serialize therefore shipped unescaped, and the frontend reviver silently corrupted user data that collided with a sentinel: "__reflex_nan__" became NaN, "__reflex_esc__x" became "x". Route both fallbacks through _json_dumps_socket_fallback, whose re-dump passes a walking default= callback so serializer output is escaped the same way the orjson path's _default_walked already does. The fast path (single dump + prefix scan) is unchanged. Regression tests use the real wire shape ["event", StateUpdate(delta)] and fail against the previous implementation on all three paths.
Both orjson.dumps passes fell back to the same stdlib path on TypeError; one try block covering the whole orjson section says that once. Behavior unchanged: any payload orjson cannot represent (e.g. int > 64-bit) takes _json_dumps_socket_fallback regardless of which pass it surfaced in.
There was a problem hiding this comment.
3 issues found across 35 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/reflex-base/src/reflex_base/plugins/shared_tailwind.py">
<violation number="1" location="packages/reflex-base/src/reflex_base/plugins/shared_tailwind.py:94">
P2: Tailwind theme values or plugin arguments containing `NaN`/`Infinity` now become `null`, silently changing the generated JavaScript configuration. Since this output is JavaScript rather than strict JSON, consider retaining stdlib `json.dumps` here or using a serializer that preserves these valid JS numeric tokens.</violation>
</file>
<file name="packages/reflex-base/src/reflex_base/.templates/web/utils/state.js">
<violation number="1" location="packages/reflex-base/src/reflex_base/.templates/web/utils/state.js:493">
P2: State values from a custom `App.sio` can be corrupted: legitimate `__reflex_nan__`, `__reflex_inf__`, or `__reflex_neg_inf__` strings are revived even though that server was never configured to escape collisions. Consider configuring provided `AsyncServer` instances with the sentinel-aware serializer, or marking sentinel-encoded packets before applying this reviver.</violation>
</file>
<file name="packages/reflex-base/src/reflex_base/utils/format.py">
<violation number="1" location="packages/reflex-base/src/reflex_base/utils/format.py:724">
P1: Reflex serializers are bypassed whenever orjson natively supports a value: `orjson_dumps` changes datetime formatting, and both fast paths skip custom Enum serializers. Route these native types through the serializer registry or retain `json_dumps` for them so generated values and socket deltas preserve existing semantics.</violation>
</file>
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
| import json | ||
| import os | ||
| import re | ||
| from functools import lru_cache |
There was a problem hiding this comment.
P1: Reflex serializers are bypassed whenever orjson natively supports a value: orjson_dumps changes datetime formatting, and both fast paths skip custom Enum serializers. Route these native types through the serializer registry or retain json_dumps for them so generated values and socket deltas preserve existing semantics.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/reflex-base/src/reflex_base/utils/format.py, line 724:
<comment>Reflex serializers are bypassed whenever orjson natively supports a value: `orjson_dumps` changes datetime formatting, and both fast paths skip custom Enum serializers. Route these native types through the serializer registry or retain `json_dumps` for them so generated values and socket deltas preserve existing semantics.</comment>
<file context>
@@ -683,6 +688,210 @@ def json_dumps(obj: Any, **kwargs) -> str:
+ option |= orjson.OPT_SORT_KEYS
+
+ try:
+ return orjson.dumps(obj, option=option or None).decode()
+ except TypeError:
+ # json_dumps handles large integers and registered custom types.
</file context>
| @@ -91,7 +91,7 @@ def tailwind_config_js_template( | |||
| Returns: | |||
There was a problem hiding this comment.
P2: Tailwind theme values or plugin arguments containing NaN/Infinity now become null, silently changing the generated JavaScript configuration. Since this output is JavaScript rather than strict JSON, consider retaining stdlib json.dumps here or using a serializer that preserves these valid JS numeric tokens.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/reflex-base/src/reflex_base/plugins/shared_tailwind.py, line 94:
<comment>Tailwind theme values or plugin arguments containing `NaN`/`Infinity` now become `null`, silently changing the generated JavaScript configuration. Since this output is JavaScript rather than strict JSON, consider retaining stdlib `json.dumps` here or using a serializer that preserves these valid JS numeric tokens.</comment>
<file context>
@@ -91,7 +91,7 @@ def tailwind_config_js_template(
The Tailwind config template.
"""
- import json
+ from reflex_base.utils.format import orjson_dumps
# Extract parameters
</file context>
There was a problem hiding this comment.
7 issues found across 35 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/reflex-components-core/pyproject.toml">
<violation number="1" location="packages/reflex-components-core/pyproject.toml:11">
P1: Publishing this package can fail because the new minimum dependency is a dev build (`*.dev0`) instead of a publishable release. Using a stable minimum version for `reflex-base` keeps `--check-dev-pins` green and avoids release-time blocking.</violation>
</file>
<file name="packages/reflex-base/src/reflex_base/.templates/web/utils/helpers/json.js">
<violation number="1" location="packages/reflex-base/src/reflex_base/.templates/web/utils/helpers/json.js:53">
P3: Malformed payloads currently do an unnecessary second full parse attempt before failing. The unconditional retry in `catch` increases CPU work on hot paths like streaming upload chunks; retrying only when the rewrite actually changes `str` keeps non-finite support without the extra failure-path cost.</violation>
</file>
<file name="packages/reflex-base/src/reflex_base/utils/format.py">
<violation number="1" location="packages/reflex-base/src/reflex_base/utils/format.py:763">
P2: Large integer values can be silently corrupted when orjson is installed, because `orjson_loads` always dispatches to `orjson.loads` even for payloads that may contain >64-bit ints. A safe fallback path (or an explicit guard for known large-int payloads) would keep behavior aligned with the documented expectation and avoid precision loss.</violation>
<violation number="2" location="packages/reflex-base/src/reflex_base/utils/format.py:894">
P2: The socket fast-path shortcut is defeated by the very payloads this PR is optimizing. The `b"null" not in out` check is meant to catch NaN/Inf (which orjson serializes as `null`), but it also fires for any genuine `None` in the state delta — common for unset/optional vars. In those cases the code pays for a full `_replace_non_finite_floats` graph walk plus a second `orjson.dumps`, roughly doubling the serialization cost of typical state-update packets and undercutting the performance goal the news file states. Consider detecting non-finite floats precisely (e.g. a dedicated scan that distinguishes NaN/Inf from plain null) instead of relying on the raw `null` byte pattern, so common null-containing payloads still hit the single-pass path.</violation>
</file>
<file name="reflex/utils/frontend_skeleton.py">
<violation number="1" location="reflex/utils/frontend_skeleton.py:368">
P2: A damaged `.web/package.json` can now abort lockfile sync instead of being overwritten. The new direct UTF-8 read in the equality check is unguarded, so decode errors stop the recovery path.</violation>
<violation number="2" location="reflex/utils/frontend_skeleton.py:424">
P2: Malformed-encoding `package.json` files can now crash initialization instead of being treated as empty. The new UTF-8 decode path raises `UnicodeDecodeError`, but the handler only catches JSON/OSError, so this code path no longer matches the function’s fallback behavior.</violation>
</file>
<file name="packages/reflex-base/src/reflex_base/compiler/templates.py">
<violation number="1" location="packages/reflex-base/src/reflex_base/compiler/templates.py:535">
P3: Heads-up on reproducibility: these generated/config files (`.web/package.json`, `react-router.config.js`, the inlined clientStorage/isDevMode JS, and `cpu_info.json`) are now rendered with `orjson_dumps`, whose output depends on whether the optional `orjson` extra is installed. With orjson present you get compact UTF-8 (`{"a":1}`); without it, the fallback `json_dumps` emits spaced output (`{"a": 1}`) and different float handling. The same source tree will therefore produce byte-different artifacts across environments (and the strict string equality in `sync_root_package_json_to_web` can then see package.json as 'changed' when the extra flips). Consider forcing a canonical format for artifacts written to disk (e.g. always route these through an explicit `orjson_dumps(..., indent=2)`/fixed separator path, or serialize package.json/config deterministically regardless of optional-dependency presence) so outputs are stable.</violation>
</file>
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
| requires-python = ">=3.10" | ||
| dependencies = [ | ||
| "reflex-base >= 0.9.7", | ||
| "reflex-base >= 0.9.8.post37.dev0", |
There was a problem hiding this comment.
P1: Publishing this package can fail because the new minimum dependency is a dev build (*.dev0) instead of a publishable release. Using a stable minimum version for reflex-base keeps --check-dev-pins green and avoids release-time blocking.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/reflex-components-core/pyproject.toml, line 11:
<comment>Publishing this package can fail because the new minimum dependency is a dev build (`*.dev0`) instead of a publishable release. Using a stable minimum version for `reflex-base` keeps `--check-dev-pins` green and avoids release-time blocking.</comment>
<file context>
@@ -8,7 +8,7 @@ authors = [{ name = "Khaleel Al-Adhami", email = "khaleel@reflex.dev" }]
requires-python = ">=3.10"
dependencies = [
- "reflex-base >= 0.9.7",
+ "reflex-base >= 0.9.8.post37.dev0",
"reflex-components-lucide >= 0.9.0",
"reflex-components-sonner >= 0.9.0",
</file context>
| "reflex-base >= 0.9.8.post37.dev0", | |
| "reflex-base >= 0.9.8", |
| """ | ||
| if orjson is None: | ||
| return json.loads(data) | ||
| return orjson.loads(data) |
There was a problem hiding this comment.
P2: Large integer values can be silently corrupted when orjson is installed, because orjson_loads always dispatches to orjson.loads even for payloads that may contain >64-bit ints. A safe fallback path (or an explicit guard for known large-int payloads) would keep behavior aligned with the documented expectation and avoid precision loss.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/reflex-base/src/reflex_base/utils/format.py, line 763:
<comment>Large integer values can be silently corrupted when orjson is installed, because `orjson_loads` always dispatches to `orjson.loads` even for payloads that may contain >64-bit ints. A safe fallback path (or an explicit guard for known large-int payloads) would keep behavior aligned with the documented expectation and avoid precision loss.</comment>
<file context>
@@ -683,6 +688,221 @@ def json_dumps(obj: Any, **kwargs) -> str:
+ """
+ if orjson is None:
+ return json.loads(data)
+ return orjson.loads(data)
+
+
</file context>
|
|
||
| try: | ||
| out = orjson.dumps(obj, default=_default_fast, option=_ORJSON_SOCKET_OPTS) | ||
| if b"null" not in out and _SENTINEL_PREFIX_BYTES not in out: |
There was a problem hiding this comment.
P2: The socket fast-path shortcut is defeated by the very payloads this PR is optimizing. The b"null" not in out check is meant to catch NaN/Inf (which orjson serializes as null), but it also fires for any genuine None in the state delta — common for unset/optional vars. In those cases the code pays for a full _replace_non_finite_floats graph walk plus a second orjson.dumps, roughly doubling the serialization cost of typical state-update packets and undercutting the performance goal the news file states. Consider detecting non-finite floats precisely (e.g. a dedicated scan that distinguishes NaN/Inf from plain null) instead of relying on the raw null byte pattern, so common null-containing payloads still hit the single-pass path.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/reflex-base/src/reflex_base/utils/format.py, line 894:
<comment>The socket fast-path shortcut is defeated by the very payloads this PR is optimizing. The `b"null" not in out` check is meant to catch NaN/Inf (which orjson serializes as `null`), but it also fires for any genuine `None` in the state delta — common for unset/optional vars. In those cases the code pays for a full `_replace_non_finite_floats` graph walk plus a second `orjson.dumps`, roughly doubling the serialization cost of typical state-update packets and undercutting the performance goal the news file states. Consider detecting non-finite floats precisely (e.g. a dedicated scan that distinguishes NaN/Inf from plain null) instead of relying on the raw `null` byte pattern, so common null-containing payloads still hit the single-pass path.</comment>
<file context>
@@ -683,6 +688,221 @@ def json_dumps(obj: Any, **kwargs) -> str:
+
+ try:
+ out = orjson.dumps(obj, default=_default_fast, option=_ORJSON_SOCKET_OPTS)
+ if b"null" not in out and _SENTINEL_PREFIX_BYTES not in out:
+ return out.decode()
+ return orjson.dumps(
</file context>
| # Ensure "type" is not duplicated since it's always set to "module" | ||
| additional_keys.pop("type", None) | ||
| return json.dumps({ | ||
| return orjson_dumps({ |
There was a problem hiding this comment.
P3: Heads-up on reproducibility: these generated/config files (.web/package.json, react-router.config.js, the inlined clientStorage/isDevMode JS, and cpu_info.json) are now rendered with orjson_dumps, whose output depends on whether the optional orjson extra is installed. With orjson present you get compact UTF-8 ({"a":1}); without it, the fallback json_dumps emits spaced output ({"a": 1}) and different float handling. The same source tree will therefore produce byte-different artifacts across environments (and the strict string equality in sync_root_package_json_to_web can then see package.json as 'changed' when the extra flips). Consider forcing a canonical format for artifacts written to disk (e.g. always route these through an explicit orjson_dumps(..., indent=2)/fixed separator path, or serialize package.json/config deterministically regardless of optional-dependency presence) so outputs are stable.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/reflex-base/src/reflex_base/compiler/templates.py, line 535:
<comment>Heads-up on reproducibility: these generated/config files (`.web/package.json`, `react-router.config.js`, the inlined clientStorage/isDevMode JS, and `cpu_info.json`) are now rendered with `orjson_dumps`, whose output depends on whether the optional `orjson` extra is installed. With orjson present you get compact UTF-8 (`{"a":1}`); without it, the fallback `json_dumps` emits spaced output (`{"a": 1}`) and different float handling. The same source tree will therefore produce byte-different artifacts across environments (and the strict string equality in `sync_root_package_json_to_web` can then see package.json as 'changed' when the extra flips). Consider forcing a canonical format for artifacts written to disk (e.g. always route these through an explicit `orjson_dumps(..., indent=2)`/fixed separator path, or serialize package.json/config deterministically regardless of optional-dependency presence) so outputs are stable.</comment>
<file context>
@@ -533,7 +532,7 @@ def package_json_template(
# Ensure "type" is not duplicated since it's always set to "module"
additional_keys.pop("type", None)
- return json.dumps({
+ return orjson_dumps({
"name": additional_keys.pop("name", "reflex"),
"type": "module",
</file context>
There was a problem hiding this comment.
1 issue found across 35 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="reflex/utils/frontend_skeleton.py">
<violation number="1" location="reflex/utils/frontend_skeleton.py:600">
P2: A persisted `package.json` with `"overrides": null` is treated as `{}` above, and this write then replaces the user's malformed locked file with framework overrides instead of preserving it. Leaving the file untouched when `overrides` is not a mapping would let the user fix or remove it before dependency resolution.
(Based on your team's feedback about preserving user-locked package.json files with malformed overrides.)</violation>
</file>
Tip: cubic used a learning from your PR history. Let your coding agent read cubic learnings directly with the cubic MCP.
Re-trigger cubic
| package_json["overrides"] = {**overrides, **constants.PackageJson.OVERRIDES} | ||
| console.debug(f"Applying framework overrides to {package_json_path}") | ||
| package_json_path.write_text(json.dumps(package_json)) | ||
| package_json_path.write_text(orjson_dumps(package_json), encoding="utf-8") |
There was a problem hiding this comment.
P2: A persisted package.json with "overrides": null is treated as {} above, and this write then replaces the user's malformed locked file with framework overrides instead of preserving it. Leaving the file untouched when overrides is not a mapping would let the user fix or remove it before dependency resolution.
(Based on your team's feedback about preserving user-locked package.json files with malformed overrides.)
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At reflex/utils/frontend_skeleton.py, line 600:
<comment>A persisted `package.json` with `"overrides": null` is treated as `{}` above, and this write then replaces the user's malformed locked file with framework overrides instead of preserving it. Leaving the file untouched when `overrides` is not a mapping would let the user fix or remove it before dependency resolution.
(Based on your team's feedback about preserving user-locked package.json files with malformed overrides.) </comment>
<file context>
@@ -593,14 +597,16 @@ def update_package_json_overrides() -> bool:
package_json["overrides"] = {**overrides, **constants.PackageJson.OVERRIDES}
console.debug(f"Applying framework overrides to {package_json_path}")
- package_json_path.write_text(json.dumps(package_json))
+ package_json_path.write_text(orjson_dumps(package_json), encoding="utf-8")
return True
</file context>
…ex-dev#6854) * Upgrade react-router to 8.3.0 Moves the frontend from react-router 7.18.2 to 8.3.0 and adopts the new baseline it requires: - Node `MIN_VERSION` 22.12.0 -> 22.22.0 (`engines.node` of react-router 8) - Drop `react-router-dom`, removed upstream in v8. Nothing in the framework imported it; the existing stale-package pruning in `_install_frontend_packages` removes it from projects on next install. The React 19.2.7+ peer floor and Vite 7+ floor are already met by the current 19.2.8 and 8.0.16 pins, so neither moves here. Vite stays at 8.0.16 per the existing memo-rerender note. No other source changes were needed. Reflex sets no `future.v8_*` flags, so the behaviors those flags now enable by default (middleware, pass-through requests, trailing-slash-aware data requests, the Vite Environment API build path, and `splitRouteModules`) apply without config changes. Generated route modules export only a default component -- no `meta`, `loader`, or `hasErrorBoundary` -- so the `meta` `data`/`loaderData` rename, the `RouterContextProvider` context change, and the `hasErrorBoundary` removal are all inapplicable. `future.unstable_optimizeDeps` remains a valid v8 config key. Verified by building and running a multi-page app (state, websocket event round trip, `Link` client-side navigation, dynamic route, 404 fallback) in dev and prod modes, plus the embed entry's `createMemoryRouter`/`RouterProvider` path in a host page. Also confirmed the `patchReactRouterHmrRuntime` vite plugin (reflex-dev#6774) still applies: its regex matches 8.3.0's hmr runtime, the plugin's "hmr runtime changed" skip warning never fires, and the wedge it fixes does not recur -- editing an unloaded route then a loaded one still hot updates. That patch fails open, so a silent regex miss would have quietly reintroduced the bug. Adds tests pinning the upstream Node/React/Vite floors, which otherwise live only in react-router's manifest, so a future partial bump fails loudly instead of at install time. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ZJDfyvTWhhJ25Lpch4VmS * Correct the vite version claim in the reflex-base 0.9.8 changelog The 0.9.8 dependency-bump entry lists `vite: 8.0.16 -> 8.2.0`, but that bump was reverted before reflex-dev#6678 merged -- vite 8.2.0 reintroduces a memoized-component re-render regression, which is why the pin still carries a comment holding it at 8.0.16. The news fragment was not updated alongside the revert, so the released notes claim an upgrade that never shipped. Drops that line, and drops the "(also satisfying `vite` 8.2.0's `^8.5.23`)" aside from the same entry's postcss-override rationale: the shipped vite is 8.0.16, which requires only `postcss@^8.5.15`. The override's actual reason -- keeping transitive resolutions on a patched release (>= 8.5.18) for the security advisory -- is unchanged and retained. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ZJDfyvTWhhJ25Lpch4VmS * Drop the framework-owned postcss package.json override `postcss` is already pinned directly in `DEV_DEPENDENCIES` (8.5.23), and a top-level pin satisfies and dedupes every transitive requirer -- `autoprefixer` (peer `^8.1.0`), `postcss-import` (peer `^8.0.0`), and vite's own dependency (`^8.5.15`). Verified: with the override removed a fresh app and the docs app both still resolve exactly one `postcss@8.5.23`, so the security-advisory floor (>= 8.5.18) that motivated the override is held by the pin alone. The override was also strictly worse to carry, which is the real reason to drop it. `update_package_json_overrides` merges framework overrides into a project's `reflex.lock/package.json` and never removes entries, so once an override ships it cannot be retired by a later release -- it becomes a vestigial pin that only user intervention can clear, and one that would actively conflict the next time the `postcss` dev pin moves past the frozen override value. `OVERRIDES` is kept as an empty mapping (the mechanism is still wired up and unit-tested) with a note to prefer a dependency pin whenever the package is one we declare directly. Projects that already installed 0.9.8 keep an inert `"postcss": "8.5.23"` override, confirmed by simulating that upgrade: the persisted entry survives, the build succeeds, and postcss still resolves to 8.5.23. It matches the dev pin, so it is a no-op until removed by hand. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ZJDfyvTWhhJ25Lpch4VmS * Scope the react-router v8 no-app-changes claim in the release note The note opened with a blanket "No rxconfig.py or app code changes are needed" and then said custom components wrapping react-router-dom must change their imports, which contradicts it. Scope the claim to apps on the default generated setup and state the react-router-dom import change as required rather than as an aside. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ZJDfyvTWhhJ25Lpch4VmS --------- Co-authored-by: Claude <noreply@anthropic.com>
No description provided.