Skip to content

Conversation

@gaoachao
Copy link
Collaborator

@gaoachao gaoachao commented Sep 24, 2025

Summary by CodeRabbit

  • Refactor

    • Reorganized React transform plugins to use a shared helpers module and a dedicated N-API boundary for the JSX transformer. Updated internal imports for clearer module structure. No user-facing behavior changes.
  • Chores

    • Added internal crates and dependencies to support modularization of the transform plugins and shared utilities.
  • Release Impact

    • No functional changes expected for end-users; build and packaging remain compatible.

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 Sep 24, 2025

🦋 Changeset detected

Latest commit: 4d44ea6

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

This PR includes changesets to release 0 packages

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

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 Sep 24, 2025

📝 Walkthrough

Walkthrough

Adds two new internal crates (swc_plugin_list, swc_plugin_snapshot), wires them into react/transform, moves shared JSX helpers into swc_plugins_shared, introduces an N-API bridge module (napi) for JSXTransformer, and updates import paths across files to use swc_plugins_shared and the new napi module. Includes a trivial changeset entry.

Changes

Cohort / File(s) Summary
Changeset
\.changeset/hot-socks-thank.md
Adds an empty changeset delimiter file (no code changes).
Cargo manifests (new crates and deps)
packages/react/transform/Cargo.toml, packages/react/transform/crates/swc_plugin_list/Cargo.toml, packages/react/transform/crates/swc_plugin_snapshot/Cargo.toml, packages/react/transform/crates/swc_plugins_shared/Cargo.toml
Adds path deps to new crates; introduces swc_plugin_list and swc_plugin_snapshot manifests; updates swc_plugins_shared deps (once_cell, regex).
Import path refactor to shared helpers and napi
packages/react/transform/crates/swc_plugin_list/lib.rs, packages/react/transform/crates/swc_plugin_snapshot/lib.rs, packages/react/transform/crates/swc_plugin_snapshot/slot_marker.rs, packages/react/transform/src/lib.rs
Redirects imports from local modules to swc_plugins_shared and swc_plugin_snapshot::napi; removes public jsx_helpers export from snapshot; updates module declarations accordingly.
New N-API wrapper
packages/react/transform/crates/swc_plugin_snapshot/napi.rs
Adds N-API-facing JSXTransformerConfig and generic JSXTransformer<C> with conversions and VisitMut delegation.
Shared helpers export
packages/react/transform/crates/swc_plugins_shared/lib.rs
Exposes new public jsx_helpers module.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

framework:React

Suggested reviewers

  • upupming
  • colinaaa

Poem

I hop through crates, a tidy sweep,
New napi burrows, tunnels deep.
Shared helpers bloom where imports tread,
Snapshot sheds an old thread.
Rusty roots entwine just right—
Transform paths now crisp and light. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly and accurately summarizes the primary change: extracting the swc_plugin_snapshot and swc_plugin_list components; the diff shows new crates, moved modules, and updated imports consistent with that refactor. It is concise, specific, and easy for a teammate to scan in history.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/extract-swc-plugin-snapshot

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.

@codecov
Copy link

codecov bot commented Sep 24, 2025

Codecov Report

❌ Patch coverage is 57.14286% with 21 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...react/transform/crates/swc_plugin_snapshot/napi.rs 57.14% 21 Missing ⚠️

📢 Thoughts on this report? Let us know!

@relativeci
Copy link

relativeci bot commented Sep 24, 2025

React Example

#5490 Bundle Size — 237.5KiB (0%).

4d44ea6(current) vs 69e0dc4 main#5481(baseline)

Bundle metrics  no changes
                 Current
#5490
     Baseline
#5481
No change  Initial JS 0B 0B
No change  Initial CSS 0B 0B
No change  Cache Invalidation 0% 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.76% 46.76%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#5490
     Baseline
#5481
No change  IMG 145.76KiB 145.76KiB
No change  Other 91.74KiB 91.74KiB

Bundle analysis reportBranch refactor/extract-swc-plugin-snap...Project dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link

relativeci bot commented Sep 24, 2025

Web Explorer

#5484 Bundle Size — 365.4KiB (0%).

4d44ea6(current) vs 69e0dc4 main#5475(baseline)

Bundle metrics  no changes
                 Current
#5484
     Baseline
#5475
No change  Initial JS 145.69KiB 145.69KiB
No change  Initial CSS 32KiB 32KiB
No change  Cache Invalidation 0% 0%
No change  Chunks 8 8
No change  Assets 8 8
No change  Modules 220 220
No change  Duplicate Modules 16 16
No change  Duplicate Code 3.37% 3.37%
No change  Packages 4 4
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#5484
     Baseline
#5475
No change  JS 239.39KiB 239.39KiB
No change  Other 94.02KiB 94.02KiB
No change  CSS 32KiB 32KiB

Bundle analysis reportBranch refactor/extract-swc-plugin-snap...Project dashboard


Generated by RelativeCIDocumentationReport issue

@codspeed-hq
Copy link

codspeed-hq bot commented Sep 24, 2025

CodSpeed Performance Report

Merging #1819 will degrade performances by 6.73%

Comparing refactor/extract-swc-plugin-snapshot (4d44ea6) with main (69e0dc4)

Summary

⚡ 1 improvement
❌ 3 regressions
✅ 49 untouched
⏩ 3 skipped1

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

Benchmarks breakdown

Benchmark BASE HEAD Change
transform 1000 view elements 43.8 ms 41.7 ms +5.07%
basic-performance-div-100 5.9 ms 6.3 ms -6.73%
basic-performance-div-10000 385.1 ms 408.8 ms -5.81%
basic-performance-small-css 6.8 ms 7.2 ms -6.4%

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.

@gaoachao gaoachao marked this pull request as ready for review September 24, 2025 08:11
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

🧹 Nitpick comments (2)
packages/react/transform/crates/swc_plugin_snapshot/lib.rs (1)

25-25: napi module exposure

Good separation. Consider re-exporting the napi types at crate root to reduce consumer churn.

Example:

+pub use napi::{JSXTransformer as NapiJSXTransformer, JSXTransformerConfig as NapiJSXTransformerConfig};
packages/react/transform/crates/swc_plugin_snapshot/napi.rs (1)

31-42: Reduce duplication: derive defaults from core config to avoid drift.

Keep one source of truth by delegating to CoreJSXTransformerConfig::default().

-impl Default for JSXTransformerConfig {
-  fn default() -> Self {
-    Self {
-      preserve_jsx: false,
-      runtime_pkg: "@lynx-js/react".into(),
-      jsx_import_source: Some("@lynx-js/react".into()),
-      filename: Default::default(),
-      target: TransformTarget::LEPUS,
-      is_dynamic_component: Some(false),
-    }
-  }
-}
+impl Default for JSXTransformerConfig {
+  fn default() -> Self {
+    CoreJSXTransformerConfig::default().into()
+  }
+}
📜 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 69e0dc4 and 4d44ea6.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (11)
  • .changeset/hot-socks-thank.md (1 hunks)
  • packages/react/transform/Cargo.toml (1 hunks)
  • packages/react/transform/crates/swc_plugin_list/Cargo.toml (1 hunks)
  • packages/react/transform/crates/swc_plugin_list/lib.rs (2 hunks)
  • packages/react/transform/crates/swc_plugin_snapshot/Cargo.toml (1 hunks)
  • packages/react/transform/crates/swc_plugin_snapshot/lib.rs (2 hunks)
  • packages/react/transform/crates/swc_plugin_snapshot/napi.rs (1 hunks)
  • packages/react/transform/crates/swc_plugin_snapshot/slot_marker.rs (1 hunks)
  • packages/react/transform/crates/swc_plugins_shared/Cargo.toml (1 hunks)
  • packages/react/transform/crates/swc_plugins_shared/lib.rs (1 hunks)
  • packages/react/transform/src/lib.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
.changeset/*.md

📄 CodeRabbit inference engine (AGENTS.md)

For contributions, always generate a changeset and commit the resulting markdown file(s)

Files:

  • .changeset/hot-socks-thank.md
🧠 Learnings (8)
📓 Common learnings
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.407Z
Learning: In packages/react/transform/src/swc_plugin_compat/mod.rs, the `add_pure_comment` function at 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. These are two distinct code paths that should be treated differently.
📚 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/transform/crates/swc_plugins_shared/lib.rs
  • packages/react/transform/crates/swc_plugin_snapshot/slot_marker.rs
  • packages/react/transform/src/lib.rs
  • packages/react/transform/crates/swc_plugin_snapshot/napi.rs
  • packages/react/transform/crates/swc_plugin_snapshot/lib.rs
  • packages/react/transform/crates/swc_plugin_list/lib.rs
📚 Learning: 2025-09-18T04:43:54.407Z
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.407Z
Learning: In packages/react/transform/src/swc_plugin_compat/mod.rs, the `add_pure_comment` function at 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. These are two distinct code paths that should be treated differently.

Applied to files:

  • packages/react/transform/crates/swc_plugin_snapshot/slot_marker.rs
  • packages/react/transform/src/lib.rs
  • packages/react/transform/crates/swc_plugin_snapshot/napi.rs
  • packages/react/transform/crates/swc_plugin_snapshot/lib.rs
📚 Learning: 2025-09-18T04:43:54.407Z
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.407Z
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:

  • packages/react/transform/crates/swc_plugin_snapshot/slot_marker.rs
  • packages/react/transform/src/lib.rs
  • packages/react/transform/crates/swc_plugin_snapshot/napi.rs
  • packages/react/transform/crates/swc_plugin_snapshot/lib.rs
📚 Learning: 2025-09-10T11:42:36.855Z
Learnt from: gaoachao
PR: lynx-family/lynx-stack#1714
File: packages/react/transform/Cargo.toml:19-19
Timestamp: 2025-09-10T11:42:36.855Z
Learning: In packages/react/transform/Cargo.toml, the crate uses serde derive macros (#[derive(Serialize, Deserialize)]) in multiple files including src/esbuild.rs and src/swc_plugin_extract_str/mod.rs, so the "derive" feature is required when migrating to workspace dependencies.

Applied to files:

  • packages/react/transform/crates/swc_plugin_snapshot/Cargo.toml
  • packages/react/transform/crates/swc_plugin_list/Cargo.toml
  • packages/react/transform/Cargo.toml
  • packages/react/transform/crates/swc_plugins_shared/Cargo.toml
  • packages/react/transform/src/lib.rs
📚 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, empty changeset files (containing only `---\n\n---`) are used for internal changes that modify src/** files but don't require meaningful release notes, such as private package changes or testing-only modifications. This satisfies CI requirements without generating user-facing release notes.

Applied to files:

  • .changeset/hot-socks-thank.md
📚 Learning: 2025-07-22T09:26:16.722Z
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:26:16.722Z
Learning: In the lynx-family/lynx-stack repository, CI checks require changesets when files matching the pattern "src/**" are modified (as configured in .changeset/config.json). For internal changes that don't need meaningful changesets, an empty changeset file is used to satisfy the CI requirement while not generating any release notes.

Applied to files:

  • .changeset/hot-socks-thank.md
📚 Learning: 2025-09-09T12:38:10.450Z
Learnt from: CR
PR: lynx-family/lynx-stack#0
File: AGENTS.md:0-0
Timestamp: 2025-09-09T12:38:10.450Z
Learning: Applies to .changeset/*.md : For contributions, always generate a changeset and commit the resulting markdown file(s)

Applied to files:

  • .changeset/hot-socks-thank.md
🧬 Code graph analysis (5)
packages/react/transform/crates/swc_plugins_shared/lib.rs (1)
packages/react/transform/src/swc_plugin_snapshot/mod.rs (1)
  • jsx_helpers (23-23)
packages/react/transform/crates/swc_plugin_snapshot/slot_marker.rs (1)
packages/react/transform/crates/swc_plugins_shared/jsx_helpers.rs (7)
  • jsx_children_to_expr (162-205)
  • jsx_has_dynamic_key (219-239)
  • jsx_is_children_full_dynamic (255-314)
  • jsx_is_custom (207-217)
  • jsx_is_list (241-246)
  • jsx_name (13-74)
  • jsx_text_to_str (130-160)
packages/react/transform/crates/swc_plugin_snapshot/napi.rs (1)
packages/react/transform/crates/swc_plugin_snapshot/lib.rs (8)
  • default (990-999)
  • with_content_hash (1024-1027)
  • new (257-272)
  • new (1029-1051)
  • visit_mut_jsx_element (358-944)
  • visit_mut_jsx_element (1097-1488)
  • visit_mut_module_items (1490-1503)
  • visit_mut_module (1505-1538)
packages/react/transform/crates/swc_plugin_snapshot/lib.rs (2)
packages/react/transform/crates/swc_plugins_shared/css.rs (1)
  • get_string_inline_style_from_literal (14-64)
packages/react/transform/crates/swc_plugins_shared/jsx_helpers.rs (12)
  • jsx_attr_name (76-81)
  • jsx_attr_to_prop (99-110)
  • jsx_attr_value (83-97)
  • jsx_children_to_expr (162-205)
  • jsx_is_children_full_dynamic (255-314)
  • jsx_is_custom (207-217)
  • jsx_is_list (241-246)
  • jsx_is_list_item (248-253)
  • jsx_name (13-74)
  • jsx_props_to_obj (112-128)
  • jsx_text_to_str (130-160)
  • transform_jsx_attr_str (317-360)
packages/react/transform/crates/swc_plugin_list/lib.rs (1)
packages/react/transform/crates/swc_plugins_shared/jsx_helpers.rs (3)
  • jsx_attr_value (83-97)
  • jsx_children_to_expr (162-205)
  • jsx_is_list_item (248-253)
🔇 Additional comments (19)
.changeset/hot-socks-thank.md (1)

1-3: Empty changeset is appropriate for internal refactor

Matches repo convention for src/** changes without user-facing notes.

Please confirm CI’s changeset check passes with this file name.

packages/react/transform/crates/swc_plugins_shared/lib.rs (1)

2-2: Publicly exporting jsx_helpers LGTM

Centralizing helpers here simplifies imports across plugins.

packages/react/transform/crates/swc_plugins_shared/Cargo.toml (1)

14-15: Adds required deps for jsx_helpers

once_cell and regex are needed by jsx_helpers; good addition.

packages/react/transform/Cargo.toml (1)

29-31: Wire-up of new crates

Path dependencies for swc_plugin_list and swc_plugin_snapshot look correct.

If the repo uses a top-level Cargo workspace, ensure these crates don’t also need to be added to workspace.members (usually not required for path deps nested under a member).

packages/react/transform/src/lib.rs (1)

61-61: Importing JSXTransformer via napi module

Path update aligns with the new API boundary.

Confirm swc_plugin_snapshot::napi re-exports match the used signatures (new, with_content_hash) so downstream compiles cleanly.

packages/react/transform/crates/swc_plugin_snapshot/Cargo.toml (1)

1-21: New crate manifest looks consistent with workspace deps

Feature set mirrors other transform crates and includes swc_plugins_shared.

packages/react/transform/crates/swc_plugin_list/Cargo.toml (1)

1-13: New list plugin crate manifest LGTM

Dependencies align with usage: swc_core, swc_plugin_snapshot, swc_plugins_shared.

packages/react/transform/crates/swc_plugin_snapshot/lib.rs (3)

27-38: Shared imports consolidation LGTM

Moving JSX helpers, target, mode, and utils under swc_plugins_shared is the right direction.


39-42: Local module boundary

attr_name and slot_marker remain internal; no issues spotted.


1566-1567: Test imports remain from crate root

Consistent with keeping core transformer types internal while exposing napi for external use.

Ensure napi::JSXTransformer maps to the same behavior as crate::JSXTransformer used in tests (type alias or wrapper), to prevent divergence.

packages/react/transform/crates/swc_plugin_list/lib.rs (2)

11-11: Imports realigned to shared helpers — looks good.

Moving to swc_plugins_shared::jsx_helpers is correct and matches the new module structure.


192-194: Ensure From/Into conversions exist for swc_plugins_shared napi enums → core types
Repository search returned no impl From/Into matches for swc_plugins_shared::transform_mode_napi::TransformMode or swc_plugins_shared::target_napi::TransformTarget — add or confirm conversions to the core TransformMode/TransformTarget used by JSXTransformer::new.

packages/react/transform/crates/swc_plugin_snapshot/napi.rs (4)

44-55: From -> Core mapping looks correct.

Field parity and conversions are aligned.


57-68: From -> napi config mapping looks correct.

Symmetric with the previous impl.


93-108: VisitMut delegation is straightforward.

Delegating element/module transforms to the inner core transformer is appropriate.


86-90: Constructor delegation is correct — verify TransformMode/TransformTarget Into/From impls exist

Repository search for impl From<swc_plugins_shared::transform_mode_napi::TransformMode> and impl From<swc_plugins_shared::target_napi::TransformTarget> returned no matches; confirm those conversions are implemented in swc_plugins_shared or add them.

packages/react/transform/crates/swc_plugin_snapshot/slot_marker.rs (3)

100-101: unreachable! for JSXSpreadChild matches team preference.

Retains the intentional unreachable! behavior for spread children per prior team decision. No action needed.


11-14: Import migration verified — no stale jsx_helpers imports remain.
All matches use swc_plugins_shared::jsx_helpers; no imports from crate|super|swc_plugin_* were found.


9-10: WRAPPER_NODE_2 import OK — single definition & parent-private visibility is sufficient

WRAPPER_NODE_2 is defined once as a static in packages/react/transform/crates/swc_plugin_snapshot/lib.rs (around line 71) and is referenced from slot_marker.rs via super::WRAPPER_NODE_2; child modules can access parent-private items, so no pub change is required and there’s no duplicate definition.

@gaoachao gaoachao merged commit 78ce4ee into main Sep 24, 2025
81 of 86 checks passed
@gaoachao gaoachao deleted the refactor/extract-swc-plugin-snapshot branch September 24, 2025 09:15
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.

3 participants