Skip to content

feat: reduce slotIndex to save json serialization time#2486

Merged
upupming merged 1 commit intomainfrom
feat/reduce-slotIndex-serialize
Apr 21, 2026
Merged

feat: reduce slotIndex to save json serialization time#2486
upupming merged 1 commit intomainfrom
feat/reduce-slotIndex-serialize

Conversation

@upupming
Copy link
Copy Markdown
Collaborator

@upupming upupming commented Apr 21, 2026

Summary by CodeRabbit

  • Refactor

    • Normalized slot-index handling and serialization across snapshot/hydration flows to improve consistency.
    • Simplified snapshot behavior to omit default slot metadata when unnecessary.
  • Tests

    • Updated numerous inline test snapshots and expectations to match the refined serialization and opcode outputs.
    • Made several tests deterministic and adjusted snapshot formats to reflect the new slot-index representation.

Checklist

  • Tests updated (or not required).
  • Documentation updated (or not required).
  • Changeset added, and when a BREAKING CHANGE occurs, it needs to be clearly marked (or not required).

@upupming upupming requested review from HuJean, Yradex and hzy as code owners April 21, 2026 07:52
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 21, 2026

⚠️ No Changeset found

Latest commit: b569462

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 21, 2026

📝 Walkthrough

Walkthrough

Normalized per-node slot-index handling: internal __slotIndex became a non-optional numeric field (default 0), serialized shape renamed/adjusted (slotIndex used in serialized forms and omitted at 0), and related snapshot, patch, hydration, and test expectations updated accordingly.

Changes

Cohort / File(s) Summary
Core snapshot implementation
packages/react/runtime/src/snapshot/snapshot.ts, packages/react/runtime/src/snapshot/backgroundSnapshot.ts, packages/react/runtime/src/snapshot/definition.ts
Make per-node __slotIndex a required number = 0; preserve it on cloning; compute isSlotV2 at snapshot creation; normalize slot resolution/insertion logic to use numeric slot indices; omit slotIndex from JSON when 0.
Serialized types
packages/react/runtime/src/snapshot/types.ts
Rename serialized property from __slotIndexslotIndex in SerializedSnapshotInstance, changing inter-thread/serialized shape.
Patch application
packages/react/runtime/src/lifecycle/patch/snapshotPatchApply.ts
SnapshotOperation.InsertBefore now reads slot index as required number (no longer optional).
Runtime tests (runtime package)
packages/react/runtime/__test__/delayed-lifecycle-events.test.jsx, packages/react/runtime/__test__/hydrate.test.jsx, packages/react/runtime/__test__/lifecycle/reload.test.jsx, packages/react/runtime/__test__/preact.test.jsx, packages/react/runtime/__test__/renderToOpcodes.test.jsx
Updated inline snapshots to remove __slotIndex occurrences, expect numeric 0 where appropriate, and adapt opcode/snapshot shapes to the new serialization.
Snapshot/patch tests
packages/react/runtime/__test__/snapshot/dynamicPartType.test.jsx, packages/react/runtime/__test__/snapshot/event.test.jsx, packages/react/runtime/__test__/snapshot/ref.test.jsx, packages/react/runtime/__test__/snapshotPatch.test.jsx
Adjusted expected opcode/patch snapshots: removed __slotIndex, normalized slotIndex defaults, and updated nested snapshot/patch tuple shapes.
Testing-library snapshots
packages/react/testing-library/src/__tests__/*
act.test.jsx, alog.test.jsx, end-to-end.test.jsx, list.test.jsx, renderComponent.test.jsx, text.test.jsx, setState-jsx.test.jsx
Removed __slotIndex from recorded snapshot expectations, adopted slotIndex naming where present, fixed a few InsertBefore expectations (null→concrete beforeId) and updated lifecycle/log payload strings.
Misc test determinism & cleanup
packages/react/runtime/__test__/renderToOpcodes.test.jsx
Made a Math.random() spy deterministic (return 0.5) and removed a stray debugger; in tests; updated snapshots accordingly.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • HuJean
  • Yradex
  • hzy

Poem

🐰 I hopped through snapshots, tidy and quick,
__slotIndex trimmed, now zero by trick.
Renamed a field, kept order in sight,
Tests adjusted with whiskers alight,
A little rabbit dance — snapshot dreams take flight!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: reducing slotIndex fields to improve JSON serialization performance, which is reflected across all modified test snapshots and source files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/reduce-slotIndex-serialize

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@upupming upupming force-pushed the feat/reduce-slotIndex-serialize branch from 1002a9a to f55b288 Compare April 21, 2026 07:54
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 21, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/react/runtime/src/lifecycle/patch/snapshotPatchApply.ts (1)

36-50: ⚠️ Potential issue | 🟡 Minor

Type cast to number doesn't safely handle undefined—add explicit null coalescing or type guard.

The param definition in snapshotPatch.ts (line 34) documents slotIndex as /* number | undefined */, but line 40 of snapshotPatchApply.ts casts unsafely: const __slotIndex = snapshotPatch[++i] as number;. All current producers push numeric values (via direct __slotIndex or slotIndex ?? 0), and the SnapshotInstance field defaults to 0, so the risk is limited. However, the cast should reflect reality. Either:

  • Use explicit null coalescing: const __slotIndex = (snapshotPatch[++i] as number | undefined) ?? 0;
  • Or update the type definition to /* number */ if undefined is impossible.

Note: Patch streams with lower reloadVersion are filtered out in updateMainThread.ts, so true cross-version replay of old patches is not a supported scenario.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react/runtime/src/lifecycle/patch/snapshotPatchApply.ts` around
lines 36 - 50, The InsertBefore case reads a possibly-undefined slot index
unsafely; change how __slotIndex is derived in snapshotPatchApply.ts (case
SnapshotOperation.InsertBefore) to handle number | undefined from snapshotPatch
by coercing to 0 when absent (e.g., read as number | undefined and use null
coalescing) before assigning to child.__slotIndex and calling
parent.insertBefore; this uses the existing snapshotPatch array, the __slotIndex
variable, and snapshotInstanceManager/child to locate the fix without altering
other logic.
packages/react/runtime/__test__/renderToOpcodes.test.jsx (1)

267-303: ⚠️ Potential issue | 🟡 Minor

Restore the Math.random spy after this test.

Line 268 installs a global spy with vi.spyOn(Math, 'random').mockReturnValue(0.5), but the suite's afterEach only calls vi.clearAllMocks(), which clears call history but does not restore the original implementation. Later tests that call Math.random() will continue receiving 0.5 instead of random values, affecting their behavior and snapshot validity.

Use mockRestore() in a try/finally block to ensure the spy is cleaned up after this test:

Proposed fix
 it('should render with attr', () => {
-  vi.spyOn(Math, 'random').mockReturnValue(0.5);
-  const random = Math.random();
+  const randomSpy = vi.spyOn(Math, 'random').mockReturnValue(0.5);
+  try {
+    const random = Math.random();

-  function App() {
-    return (
-      <view random={random}>
-        <text>Hello World</text>
-        <raw-text text={'Hello World'.toLowerCase()} />
-      </view>
-    );
-  }
+    function App() {
+      return (
+        <view random={random}>
+          <text>Hello World</text>
+          <raw-text text={'Hello World'.toLowerCase()} />
+        </view>
+      );
+    }

-  expect(renderToString(<App />)).toMatchInlineSnapshot(`
+    expect(renderToString(<App />)).toMatchInlineSnapshot(`
       [
         0,
         {
@@
         1,
       ]
     `);
+  } finally {
+    randomSpy.mockRestore();
+  }
 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react/runtime/__test__/renderToOpcodes.test.jsx` around lines 267 -
303, The test "should render with attr" installs a global spy via vi.spyOn(Math,
'random').mockReturnValue(0.5) but never restores the original implementation;
fix this by capturing the spy (e.g., const rndSpy = vi.spyOn(Math,
'random').mockReturnValue(0.5)), then wrap the test body in a try/finally and
call rndSpy.mockRestore() in the finally block (or use rndSpy.mockRestore()
after assertions) so Math.random is restored for subsequent tests.
🧹 Nitpick comments (2)
packages/react/runtime/src/snapshot/types.ts (1)

19-26: Runtime vs. serialized field-name divergence — document the contract.

After this rename, runtime instances use __slotIndex (see BackgroundSnapshotInstance.__slotIndex: number = 0) while the wire/serialized form uses slotIndex. That divergence is intentional (serialization drops the double-underscore prefix and omits the field when 0), and matches the asymmetric reads in backgroundSnapshot.ts (v.slotIndex ?? 0 for serialized vs v.__slotIndex for runtime). However, it's easy to mis-wire in future changes.

Recommend a short JSDoc here pointing out:

  • slotIndex corresponds to the runtime __slotIndex property.
  • It is omitted when the value is 0 to reduce JSON size.

This will make the runtime/wire invariant explicit and prevent future readers from "fixing" one side to match the other.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react/runtime/src/snapshot/types.ts` around lines 19 - 26, Add a
short JSDoc to the SerializedSnapshotInstance interface documenting that the
serialized field slotIndex maps to the runtime property __slotIndex (see
BackgroundSnapshotInstance.__slotIndex) and that slotIndex is intentionally
omitted from the wire form when its value is 0 to reduce JSON size; mention the
asymmetric reads in backgroundSnapshot.ts (uses v.slotIndex ?? 0 for
deserialization and runtime uses v.__slotIndex) so future editors don’t
accidentally try to rename/mirror the fields incorrectly.
packages/react/runtime/src/snapshot/definition.ts (1)

144-150: Consider moving isSlotV2 assignment out of the slot[0] guard.

When slot is empty (e.g., the hardcoded null text entry at line 105), isSlotV2 is left undefined rather than false. Downstream checks use this.__snapshot_def.isSlotV2 ? ... (ternary), so undefined currently behaves the same as false, but explicitly assigning false would make the invariant clearer and safer for future readers using strict equality.

Also worth double-checking: the destructure ([type]) => ... correctly targets the DynamicPartType (first element of each [type, elementIndex] tuple); the every returns true for an empty slot array, so keeping it gated by slot[0] avoids accidentally flagging empty-slot snapshots as SlotV2 — which is the current (correct) behavior. Just noting it as a subtle gotcha.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react/runtime/src/snapshot/definition.ts` around lines 144 - 150,
The isSlotV2 property can remain undefined when slot is empty; explicitly
initialize it to false and then compute it inside the existing guard to preserve
the current empty-array behavior. Concretely, set s.isSlotV2 = false before the
if (slot && slot[0]) check, and inside that block assign s.isSlotV2 =
slot.every(([type]) => type === DynamicPartType.SlotV2 || type ===
DynamicPartType.ListSlotV2); keep the guard so empty slot arrays aren’t treated
as SlotV2 and note the destructure ([type]) in the every callback is correct for
the [type, elementIndex] tuples.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/react/runtime/src/snapshot/snapshot.ts`:
- Line 91: takeElements() creates clones via Object.create which bypasses the
constructor/class-field initializer so cloned instances may lack the required
__slotIndex field or have a wrong value; update the clone creation logic in
takeElements() (and the similar clone path around the other block) to explicitly
set child.__slotIndex = source.__slotIndex (or 0 when source is undefined) after
Object.create, ensuring every cloned element has a defined numeric __slotIndex;
reference the __slotIndex field and the takeElements() clone code path when
making the change.

---

Outside diff comments:
In `@packages/react/runtime/__test__/renderToOpcodes.test.jsx`:
- Around line 267-303: The test "should render with attr" installs a global spy
via vi.spyOn(Math, 'random').mockReturnValue(0.5) but never restores the
original implementation; fix this by capturing the spy (e.g., const rndSpy =
vi.spyOn(Math, 'random').mockReturnValue(0.5)), then wrap the test body in a
try/finally and call rndSpy.mockRestore() in the finally block (or use
rndSpy.mockRestore() after assertions) so Math.random is restored for subsequent
tests.

In `@packages/react/runtime/src/lifecycle/patch/snapshotPatchApply.ts`:
- Around line 36-50: The InsertBefore case reads a possibly-undefined slot index
unsafely; change how __slotIndex is derived in snapshotPatchApply.ts (case
SnapshotOperation.InsertBefore) to handle number | undefined from snapshotPatch
by coercing to 0 when absent (e.g., read as number | undefined and use null
coalescing) before assigning to child.__slotIndex and calling
parent.insertBefore; this uses the existing snapshotPatch array, the __slotIndex
variable, and snapshotInstanceManager/child to locate the fix without altering
other logic.

---

Nitpick comments:
In `@packages/react/runtime/src/snapshot/definition.ts`:
- Around line 144-150: The isSlotV2 property can remain undefined when slot is
empty; explicitly initialize it to false and then compute it inside the existing
guard to preserve the current empty-array behavior. Concretely, set s.isSlotV2 =
false before the if (slot && slot[0]) check, and inside that block assign
s.isSlotV2 = slot.every(([type]) => type === DynamicPartType.SlotV2 || type ===
DynamicPartType.ListSlotV2); keep the guard so empty slot arrays aren’t treated
as SlotV2 and note the destructure ([type]) in the every callback is correct for
the [type, elementIndex] tuples.

In `@packages/react/runtime/src/snapshot/types.ts`:
- Around line 19-26: Add a short JSDoc to the SerializedSnapshotInstance
interface documenting that the serialized field slotIndex maps to the runtime
property __slotIndex (see BackgroundSnapshotInstance.__slotIndex) and that
slotIndex is intentionally omitted from the wire form when its value is 0 to
reduce JSON size; mention the asymmetric reads in backgroundSnapshot.ts (uses
v.slotIndex ?? 0 for deserialization and runtime uses v.__slotIndex) so future
editors don’t accidentally try to rename/mirror the fields incorrectly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0e60f9c0-57a2-4647-91ec-a747d7ee1759

📥 Commits

Reviewing files that changed from the base of the PR and between cffd0b1 and f55b288.

📒 Files selected for processing (21)
  • packages/react/runtime/__test__/delayed-lifecycle-events.test.jsx
  • packages/react/runtime/__test__/hydrate.test.jsx
  • packages/react/runtime/__test__/lifecycle/reload.test.jsx
  • packages/react/runtime/__test__/preact.test.jsx
  • packages/react/runtime/__test__/renderToOpcodes.test.jsx
  • packages/react/runtime/__test__/snapshot/dynamicPartType.test.jsx
  • packages/react/runtime/__test__/snapshot/event.test.jsx
  • packages/react/runtime/__test__/snapshot/ref.test.jsx
  • packages/react/runtime/__test__/snapshotPatch.test.jsx
  • packages/react/runtime/src/lifecycle/patch/snapshotPatchApply.ts
  • packages/react/runtime/src/snapshot/backgroundSnapshot.ts
  • packages/react/runtime/src/snapshot/definition.ts
  • packages/react/runtime/src/snapshot/snapshot.ts
  • packages/react/runtime/src/snapshot/types.ts
  • packages/react/testing-library/src/__tests__/act.test.jsx
  • packages/react/testing-library/src/__tests__/alog.test.jsx
  • packages/react/testing-library/src/__tests__/end-to-end.test.jsx
  • packages/react/testing-library/src/__tests__/list.test.jsx
  • packages/react/testing-library/src/__tests__/renderComponent.test.jsx
  • packages/react/testing-library/src/__tests__/setState-jsx.test.jsx
  • packages/react/testing-library/src/__tests__/text.test.jsx
💤 Files with no reviewable changes (2)
  • packages/react/testing-library/src/tests/end-to-end.test.jsx
  • packages/react/testing-library/src/tests/act.test.jsx

Comment thread packages/react/runtime/src/snapshot/snapshot.ts
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1002a9a52e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/react/runtime/src/snapshot/definition.ts
@upupming upupming force-pushed the feat/reduce-slotIndex-serialize branch from f55b288 to b569462 Compare April 21, 2026 08:09
@relativeci
Copy link
Copy Markdown

relativeci Bot commented Apr 21, 2026

React External

#564 Bundle Size — 583.27KiB (+0.19%).

b569462(current) vs cffd0b1 main#558(baseline)

Bundle metrics  Change 1 change
                 Current
#564
     Baseline
#558
No change  Initial JS 0B 0B
No change  Initial CSS 0B 0B
Change  Cache Invalidation 30.07% 98.34%
No change  Chunks 0 0
No change  Assets 3 3
No change  Modules 17 17
No change  Duplicate Modules 5 5
No change  Duplicate Code 8.59% 8.59%
No change  Packages 0 0
No change  Duplicate Packages 0 0
Bundle size by type  Change 1 change Regression 1 regression
                 Current
#564
     Baseline
#558
Regression  Other 583.27KiB (+0.19%) 582.19KiB

Bundle analysis reportBranch feat/reduce-slotIndex-serializeProject dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link
Copy Markdown

relativeci Bot commented Apr 21, 2026

Web Explorer

#9021 Bundle Size — 898.15KiB (0%).

b569462(current) vs cffd0b1 main#9015(baseline)

Bundle metrics  Change 2 changes
                 Current
#9021
     Baseline
#9015
No change  Initial JS 44.47KiB 44.47KiB
No change  Initial CSS 2.22KiB 2.22KiB
No change  Cache Invalidation 0% 0%
No change  Chunks 9 9
No change  Assets 11 11
Change  Modules 229(-0.43%) 230
No change  Duplicate Modules 11 11
Change  Duplicate Code 27.22%(+0.04%) 27.21%
No change  Packages 10 10
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#9021
     Baseline
#9015
No change  JS 494.3KiB 494.3KiB
No change  Other 401.63KiB 401.63KiB
No change  CSS 2.22KiB 2.22KiB

Bundle analysis reportBranch feat/reduce-slotIndex-serializeProject dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link
Copy Markdown

relativeci Bot commented Apr 21, 2026

React MTF Example

#579 Bundle Size — 195.57KiB (+0.07%).

b569462(current) vs cffd0b1 main#573(baseline)

Bundle metrics  Change 2 changes
                 Current
#579
     Baseline
#573
No change  Initial JS 0B 0B
No change  Initial CSS 0B 0B
Change  Cache Invalidation 43.08% 42.65%
No change  Chunks 0 0
No change  Assets 3 3
No change  Modules 173 173
No change  Duplicate Modules 66 66
Change  Duplicate Code 43.99%(+0.02%) 43.98%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  Change 1 change Regression 1 regression
                 Current
#579
     Baseline
#573
No change  IMG 111.23KiB 111.23KiB
Regression  Other 84.34KiB (+0.16%) 84.2KiB

Bundle analysis reportBranch feat/reduce-slotIndex-serializeProject dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link
Copy Markdown

relativeci Bot commented Apr 21, 2026

React Example

#7446 Bundle Size — 224.41KiB (+0.06%).

b569462(current) vs cffd0b1 main#7440(baseline)

Bundle metrics  Change 1 change
                 Current
#7446
     Baseline
#7440
No change  Initial JS 0B 0B
No change  Initial CSS 0B 0B
Change  Cache Invalidation 35.01% 34.74%
No change  Chunks 0 0
No change  Assets 4 4
No change  Modules 179 179
No change  Duplicate Modules 69 69
No change  Duplicate Code 44.5% 44.5%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  Change 1 change Regression 1 regression
                 Current
#7446
     Baseline
#7440
No change  IMG 145.76KiB 145.76KiB
Regression  Other 78.65KiB (+0.17%) 78.52KiB

Bundle analysis reportBranch feat/reduce-slotIndex-serializeProject dashboard


Generated by RelativeCIDocumentationReport issue

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/react/runtime/src/snapshot/backgroundSnapshot.ts (1)

596-602: Minor: add a brief comment explaining the before/after filter asymmetry.

The intentional asymmetry (v.slotIndex ?? 0) === index (serialized before) vs. v.__slotIndex === index (in-memory after) is correct — serialized nodes omit slotIndex when it is 0, while BackgroundSnapshotInstance.__slotIndex is now always an initialized number. A one-line comment here would save future readers a round-trip to snapshot.ts's toJSON().

📝 Suggested clarifying comment
             if (type === DynamicPartType.SlotV2 || type === DynamicPartType.ListSlotV2) {
+              // `before` is the serialized form where `slotIndex` is omitted when 0
+              // (see `SnapshotInstance.toJSON`); `after.__slotIndex` is always numeric.
               filteredBeforeChildNodes = beforeChildNodes.filter(v => (v.slotIndex ?? 0) === index);
               filteredAfterChildNodes = afterChildNodes.filter(v => v.__slotIndex === index);
             }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react/runtime/src/snapshot/backgroundSnapshot.ts` around lines 596 -
602, Add a one-line clarifying comment above the before/after filtering in the
DynamicPartType.ListChildren branch (where filteredBeforeChildNodes and
filteredAfterChildNodes are assigned) explaining the intentional asymmetry:
serialized nodes use (v.slotIndex ?? 0) === index because toJSON omits slotIndex
when it is 0, whereas in-memory BackgroundSnapshotInstance.__slotIndex is always
initialized as a number so we match with v.__slotIndex === index. Reference
DynamicPartType.ListChildren, filteredBeforeChildNodes, filteredAfterChildNodes,
and BackgroundSnapshotInstance.__slotIndex (see toJSON in snapshot.ts) in the
comment so future readers understand the difference.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/react/runtime/src/snapshot/backgroundSnapshot.ts`:
- Around line 596-602: Add a one-line clarifying comment above the before/after
filtering in the DynamicPartType.ListChildren branch (where
filteredBeforeChildNodes and filteredAfterChildNodes are assigned) explaining
the intentional asymmetry: serialized nodes use (v.slotIndex ?? 0) === index
because toJSON omits slotIndex when it is 0, whereas in-memory
BackgroundSnapshotInstance.__slotIndex is always initialized as a number so we
match with v.__slotIndex === index. Reference DynamicPartType.ListChildren,
filteredBeforeChildNodes, filteredAfterChildNodes, and
BackgroundSnapshotInstance.__slotIndex (see toJSON in snapshot.ts) in the
comment so future readers understand the difference.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ad115842-01d1-454c-84b8-47353c0a2b48

📥 Commits

Reviewing files that changed from the base of the PR and between f55b288 and b569462.

📒 Files selected for processing (21)
  • packages/react/runtime/__test__/delayed-lifecycle-events.test.jsx
  • packages/react/runtime/__test__/hydrate.test.jsx
  • packages/react/runtime/__test__/lifecycle/reload.test.jsx
  • packages/react/runtime/__test__/preact.test.jsx
  • packages/react/runtime/__test__/renderToOpcodes.test.jsx
  • packages/react/runtime/__test__/snapshot/dynamicPartType.test.jsx
  • packages/react/runtime/__test__/snapshot/event.test.jsx
  • packages/react/runtime/__test__/snapshot/ref.test.jsx
  • packages/react/runtime/__test__/snapshotPatch.test.jsx
  • packages/react/runtime/src/lifecycle/patch/snapshotPatchApply.ts
  • packages/react/runtime/src/snapshot/backgroundSnapshot.ts
  • packages/react/runtime/src/snapshot/definition.ts
  • packages/react/runtime/src/snapshot/snapshot.ts
  • packages/react/runtime/src/snapshot/types.ts
  • packages/react/testing-library/src/__tests__/act.test.jsx
  • packages/react/testing-library/src/__tests__/alog.test.jsx
  • packages/react/testing-library/src/__tests__/end-to-end.test.jsx
  • packages/react/testing-library/src/__tests__/list.test.jsx
  • packages/react/testing-library/src/__tests__/renderComponent.test.jsx
  • packages/react/testing-library/src/__tests__/setState-jsx.test.jsx
  • packages/react/testing-library/src/__tests__/text.test.jsx
💤 Files with no reviewable changes (2)
  • packages/react/testing-library/src/tests/act.test.jsx
  • packages/react/testing-library/src/tests/end-to-end.test.jsx
✅ Files skipped from review due to trivial changes (4)
  • packages/react/testing-library/src/tests/renderComponent.test.jsx
  • packages/react/testing-library/src/tests/text.test.jsx
  • packages/react/runtime/test/delayed-lifecycle-events.test.jsx
  • packages/react/testing-library/src/tests/alog.test.jsx
🚧 Files skipped from review as they are similar to previous changes (12)
  • packages/react/runtime/src/snapshot/definition.ts
  • packages/react/runtime/src/lifecycle/patch/snapshotPatchApply.ts
  • packages/react/testing-library/src/tests/setState-jsx.test.jsx
  • packages/react/runtime/test/preact.test.jsx
  • packages/react/runtime/src/snapshot/types.ts
  • packages/react/testing-library/src/tests/list.test.jsx
  • packages/react/runtime/test/lifecycle/reload.test.jsx
  • packages/react/runtime/test/snapshot/dynamicPartType.test.jsx
  • packages/react/runtime/test/snapshotPatch.test.jsx
  • packages/react/runtime/test/hydrate.test.jsx
  • packages/react/runtime/test/renderToOpcodes.test.jsx
  • packages/react/runtime/test/snapshot/ref.test.jsx

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b569462735

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/react/runtime/src/snapshot/backgroundSnapshot.ts
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Apr 21, 2026

Merging this PR will improve performance by 33.79%

⚡ 8 improved benchmarks
✅ 73 untouched benchmarks
⏩ 26 skipped benchmarks1

Performance Changes

Benchmark BASE HEAD Efficiency
002-hello-reactLynx__main-thread-serializeRoot 618.1 µs 567.7 µs +8.88%
003-hello-list__main-thread-transferRoot 214.1 µs 185.2 µs +15.63%
003-hello-list__main-thread-serializeRoot 4.4 ms 4.1 ms +9.05%
002-hello-reactLynx-destroyBackground 896.6 µs 670.1 µs +33.79%
006-static-raw-text__main-thread-serializeRoot 1.1 ms 1 ms +10.38%
007-four-layer-views__main-thread-serializeRoot 78.3 ms 70.4 ms +11.11%
007-four-layer-views__main-thread-transferRoot 1,176 µs 909.3 µs +29.34%
transform 1000 view elements 46.8 ms 39.9 ms +17.26%

Comparing feat/reduce-slotIndex-serialize (b569462) with main (cffd0b1)

Open in CodSpeed

Footnotes

  1. 26 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@upupming upupming enabled auto-merge (squash) April 21, 2026 08:45
@upupming upupming merged commit df87744 into main Apr 21, 2026
75 of 79 checks passed
@upupming upupming deleted the feat/reduce-slotIndex-serialize branch April 21, 2026 08:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants