Skip to content

Conversation

@gaoachao
Copy link
Collaborator

@gaoachao gaoachao commented Aug 25, 2025

Summary by CodeRabbit

  • Bug Fixes

    • Hydration now treats same-type list items with differing item-keys as an insert plus a removal instead of a single update, improving accurate change detection during hydration.
  • Documentation

    • Added a changeset and example demonstrating the updated list hydration behavior when item-keys differ.
  • Tests

    • Added test coverage validating insert+remove behavior for list-item hydration with differing item-keys.

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).

@changeset-bot
Copy link

changeset-bot bot commented Aug 25, 2025

🦋 Changeset detected

Latest commit: 32e8ce2

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@lynx-js/react Patch

Not sure what this means? Click here to learn what changesets are.

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 25, 2025

📝 Walkthrough

Walkthrough

Hydration diffing was made list-item key-aware: during ListChildren hydration, same-type elements with differing item-key now emit an insert + remove instead of an update. Changes add a changeset, a test, and runtime/hydration signature and key-resolution updates.

Changes

Cohort / File(s) Summary
Changelog
\.changeset/clear-numbers-call.md
Added a patch changeset documenting the hydration change: same-type list-items with different item-key emit insert+remove; includes an HTML example.
Tests
packages/react/runtime/__test__/list.test.jsx
Added a new test asserting insert+remove emission for same-type list-items when item-key differs; snapshot indices updated across the file due to the inserted test.
Hydration/runtime logic
packages/react/runtime/src/hydrate.ts, packages/react/runtime/src/backgroundSnapshot.ts
Made diffing key-aware for ListChildren: added isListHasItemKey flag passed to diffArrayLepus, added __listItemPlatformInfo?: PlatformInfo to Typed, introduced UNREACHABLE_ITEM_KEY_NOT_FOUND sentinel, and adjusted key-resolution to use node.__listItemPlatformInfo?.['item-key'] for ListChildren; diffArrayLepus call in backgroundSnapshot.ts now receives the new flag.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas needing extra attention:
    • Correct propagation and usage of the new isListHasItemKey boolean through diffing code.
    • The new optional __listItemPlatformInfo on Typed (public typing surface).
    • Behavior and safety of UNREACHABLE_ITEM_KEY_NOT_FOUND fallback when item-key is missing.
    • The new test and resulting snapshot renumbering in list.test.jsx.

Possibly related PRs

Suggested reviewers

  • DwwWxx

Poem

🐰 I hop through nodes and item-key streams,
When types match but keys change schemes,
I nudge an "insert", then tuck a "remove" in sight,
Hydration hums tidy — order set right. 🥕

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: use item-key as beforeMap key in diffArrayLepus' directly and accurately summarizes the main change: implementing item-key as the key for beforeMap in the diffArrayLepus function.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/list-diff-use-item-key

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 10bf8fb and 32e8ce2.

📒 Files selected for processing (1)
  • packages/react/runtime/src/hydrate.ts (6 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 1782
File: packages/react/transform/crates/swc_plugin_inject/napi.rs:31-47
Timestamp: 2025-09-19T07:37:58.778Z
Learning: User gaoachao prefers to keep refactoring PRs minimal and focused, deferring non-essential improvements to separate PRs to maintain clear scope boundaries.
📚 Learning: 2025-08-21T08:46:54.494Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1370
File: packages/webpack/cache-events-webpack-plugin/src/LynxCacheEventsRuntimeModule.ts:23-27
Timestamp: 2025-08-21T08:46:54.494Z
Learning: In Lynx webpack runtime modules, the team prioritizes performance and simplicity over defensive runtime error handling. They prefer relying on compile-time type safety (TypeScript) rather than adding runtime checks like try-catch blocks or type validation, especially for performance-critical code like cache event setup/cleanup functions.

Applied to files:

  • packages/react/runtime/src/hydrate.ts
📚 Learning: 2025-08-21T07:21:51.621Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1562
File: packages/react/transform/src/swc_plugin_snapshot/jsx_helpers.rs:261-283
Timestamp: 2025-08-21T07:21:51.621Z
Learning: In packages/react/transform/src/swc_plugin_snapshot/jsx_helpers.rs, the team prefers to keep the original unreachable! logic for JSXSpreadChild in jsx_is_children_full_dynamic function rather than implementing defensive error handling.

Applied to files:

  • packages/react/runtime/src/hydrate.ts
🧬 Code graph analysis (1)
packages/react/runtime/src/hydrate.ts (1)
packages/react/runtime/src/snapshot/platformInfo.ts (1)
  • PlatformInfo (25-35)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build / Build (Ubuntu)
  • GitHub Check: build / Build (Windows)
  • GitHub Check: test-rust / Test (Ubuntu)
🔇 Additional comments (2)
packages/react/runtime/src/hydrate.ts (2)

27-27: LGTM! Clean interface extension.

The optional __listItemPlatformInfo property appropriately extends the Typed interface to support item-key-based diffing for list children.


272-272: Correct differentiation between Children and ListChildren.

The call sites appropriately pass false for regular Children (type-based diffing) and true for ListChildren (item-key-based diffing), aligning with the PR's intent to make list item diffing key-aware.

Also applies to: 356-356


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.

@gaoachao gaoachao changed the title feat: use item key as beforeMap key in diffArrayLepus feat: use item-key as beforeMap key in diffArrayLepus Aug 25, 2025
@codecov
Copy link

codecov bot commented Aug 25, 2025

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
3640 1 3639 372
View the top 1 failed test(s) by shortest run time
react.spec.ts::reactlynx3 tests › elements › x-textarea › basic-element-x-textarea-bindinput
Stack Traces | 20.5s run time
react.spec.ts:4338:7 basic-element-x-textarea-bindinput

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@relativeci
Copy link

relativeci bot commented Aug 25, 2025

Web Explorer

#6101 Bundle Size — 366.7KiB (0%).

32e8ce2(current) vs 04f2c39 main#6100(baseline)

Bundle metrics  Change 1 change
                 Current
#6101
     Baseline
#6100
No change  Initial JS 146.2KiB 146.2KiB
No change  Initial CSS 32.22KiB 32.22KiB
No change  Cache Invalidation 0% 0%
No change  Chunks 8 8
No change  Assets 8 8
Change  Modules 219(-0.9%) 221
No change  Duplicate Modules 16 16
No change  Duplicate Code 3.21% 3.21%
No change  Packages 4 4
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#6101
     Baseline
#6100
No change  JS 240.68KiB 240.68KiB
No change  Other 93.8KiB 93.8KiB
No change  CSS 32.22KiB 32.22KiB

Bundle analysis reportBranch feat/list-diff-use-item-keyProject dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link

relativeci bot commented Aug 25, 2025

React Example

#6105 Bundle Size — 237.83KiB (+0.16%).

32e8ce2(current) vs 04f2c39 main#6104(baseline)

Bundle metrics  Change 1 change
                 Current
#6105
     Baseline
#6104
No change  Initial JS 0B 0B
No change  Initial CSS 0B 0B
Change  Cache Invalidation 38.62% 0%
No change  Chunks 0 0
No change  Assets 4 4
No change  Modules 165 165
No change  Duplicate Modules 67 67
No change  Duplicate Code 46.77% 46.77%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  Change 1 change Regression 1 regression
                 Current
#6105
     Baseline
#6104
No change  IMG 145.76KiB 145.76KiB
Regression  Other 92.07KiB (+0.41%) 91.69KiB

Bundle analysis reportBranch feat/list-diff-use-item-keyProject dashboard


Generated by RelativeCIDocumentationReport issue

@codspeed-hq
Copy link

codspeed-hq bot commented Aug 25, 2025

CodSpeed Performance Report

Merging #1598 will degrade performances by 5.92%

Comparing feat/list-diff-use-item-key (32e8ce2) with main (04f2c39)

Summary

⚡ 2 improvements
❌ 2 regressions
✅ 58 untouched
⏩ 3 skipped1

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Benchmarks breakdown

Benchmark BASE HEAD Change
002-hello-reactLynx-destroyBackground 702.1 µs 621.5 µs +12.97%
basic-performance-div-10000 382 ms 404.6 ms -5.59%
basic-performance-nest-level-100 6.7 ms 6.2 ms +8.95%
basic-performance-small-css 7.3 ms 7.8 ms -5.92%

Footnotes

  1. 3 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.

@github-actions
Copy link
Contributor

This pull request has been automatically marked as stale because it has not had recent activity. If this pull request is still relevant, please leave any comment (for example, "bump").

@github-actions github-actions bot added the stale Inactive for 30 days. Will be closed by bots. label Oct 24, 2025
@gaoachao gaoachao force-pushed the feat/list-diff-use-item-key branch from 8a5e9a5 to 491563b Compare October 30, 2025 08:54
@gaoachao
Copy link
Collaborator Author

bump

@gaoachao gaoachao marked this pull request as ready for review October 30, 2025 10:14
@gaoachao gaoachao requested a review from hzy as a code owner October 30, 2025 10:14
Copy link
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

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 53eed0a and 37667f3.

📒 Files selected for processing (4)
  • .changeset/clear-numbers-call.md (1 hunks)
  • packages/react/runtime/__test__/list.test.jsx (56 hunks)
  • packages/react/runtime/src/backgroundSnapshot.ts (1 hunks)
  • packages/react/runtime/src/hydrate.ts (6 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
.changeset/*.md

📄 CodeRabbit inference engine (AGENTS.md)

For contributions, generate and commit a Changeset describing your changes

Files:

  • .changeset/clear-numbers-call.md
🧠 Learnings (6)
📓 Common learnings
Learnt from: gaoachao
PR: lynx-family/lynx-stack#1782
File: packages/react/transform/crates/swc_plugin_inject/napi.rs:31-47
Timestamp: 2025-09-19T07:37:58.778Z
Learning: User gaoachao prefers to keep refactoring PRs minimal and focused, deferring non-essential improvements to separate PRs to maintain clear scope boundaries.
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
PR: lynx-family/lynx-stack#1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.

Applied to files:

  • .changeset/clear-numbers-call.md
📚 Learning: 2025-08-07T04:00:59.645Z
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1454
File: pnpm-workspace.yaml:46-46
Timestamp: 2025-08-07T04:00:59.645Z
Learning: In the lynx-family/lynx-stack repository, the webpack patch (patches/webpack5.101.0.patch) was created to fix issues with webpack5.99.9 but only takes effect on webpack5.100.0 and later versions. The patchedDependencies entry should use "webpack@^5.100.0" to ensure the patch applies to the correct version range.

Applied to files:

  • .changeset/clear-numbers-call.md
📚 Learning: 2025-08-19T11:25:36.127Z
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1558
File: .changeset/solid-squids-fall.md:2-2
Timestamp: 2025-08-19T11:25:36.127Z
Learning: In the lynx-family/lynx-stack repository, changesets should use the exact package name from package.json#name, not generic or unscoped names. Each package has its own specific scoped name (e.g., "lynx-js/react-transform" for packages/react/transform).

Applied to files:

  • .changeset/clear-numbers-call.md
📚 Learning: 2025-09-18T04:43:54.426Z
Learnt from: gaoachao
PR: lynx-family/lynx-stack#1771
File: packages/react/transform/tests/__swc_snapshots__/src/swc_plugin_snapshot/mod.rs/basic_component_with_static_sibling.js:2-2
Timestamp: 2025-09-18T04:43:54.426Z
Learning: In the lynx-family/lynx-stack repository, the `add_pure_comment` function in packages/react/transform/src/swc_plugin_compat/mod.rs (around lines 478-482) is specifically for `wrapWithLynxComponent` calls, not `createSnapshot` calls. The PURE comment injection for `createSnapshot` is handled separately in swc_plugin_snapshot/mod.rs.

Applied to files:

  • .changeset/clear-numbers-call.md
📚 Learning: 2025-08-21T07:21:51.621Z
Learnt from: upupming
PR: lynx-family/lynx-stack#1562
File: packages/react/transform/src/swc_plugin_snapshot/jsx_helpers.rs:261-283
Timestamp: 2025-08-21T07:21:51.621Z
Learning: In packages/react/transform/src/swc_plugin_snapshot/jsx_helpers.rs, the team prefers to keep the original unreachable! logic for JSXSpreadChild in jsx_is_children_full_dynamic function rather than implementing defensive error handling.

Applied to files:

  • packages/react/runtime/src/hydrate.ts
🧬 Code graph analysis (2)
packages/react/runtime/__test__/list.test.jsx (3)
packages/react/runtime/src/snapshot.ts (1)
  • SnapshotInstance (278-658)
packages/react/runtime/src/pendingListUpdates.ts (1)
  • __pendingListUpdates (7-44)
packages/react/runtime/src/hydrate.ts (1)
  • hydrate (222-398)
packages/react/runtime/src/hydrate.ts (1)
packages/react/runtime/src/snapshot/platformInfo.ts (1)
  • PlatformInfo (25-35)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build / Build (Windows)
  • GitHub Check: build / Build (Ubuntu)
  • GitHub Check: test-rust / Test (Ubuntu)

@gaoachao gaoachao requested review from DwwWxx and HuJean October 30, 2025 11:26
@github-actions github-actions bot removed the stale Inactive for 30 days. Will be closed by bots. label Oct 30, 2025
gaoachao and others added 2 commits November 4, 2025 14:35
Co-authored-by: Zhiyuan Hong <28915578+hzy@users.noreply.github.com>
Signed-off-by: BitterGourd <91231822+gaoachao@users.noreply.github.com>
@gaoachao gaoachao requested review from hzy and upupming November 4, 2025 09:46
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.

4 participants