Skip to content

Conversation

@colinaaa
Copy link
Collaborator

@colinaaa colinaaa commented Nov 5, 2025

Summary by CodeRabbit

  • Chores

    • Updated swc_core dependency to version 47.0.3.
    • Adjusted serde_json dependency configuration.
  • Refactor

    • Enhanced string handling across compiler plugins for robust text processing.
    • Updated AST processing logic for improved compatibility.
    • Improved import alias handling across multiple plugin modules.
    • Refined attribute and literal value transformations.

Related SWC breaking changes:

  1. Atom -> Wtf8Atom: fix(es/ast): Fix unicode unpaired surrogates handling swc-project/swc#11144

Wtf8Atom does not expose a to_string method like the old Atom does. Internally, it stores the code points of the characters. You can call code_points() to get an iterator of the code points or call to_string_lossy() to get an lossy string in which all unpaired surrogates are replaced with U+FFFD(Replacement Character).

  1. flexible AST: refactor(ast): Introduce flexible serialization encoding for AST swc-project/swc#11100

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 Nov 5, 2025

🦋 Changeset detected

Latest commit: 4f4b1eb

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 Nov 5, 2025

📝 Walkthrough

Walkthrough

This PR upgrades the swc_core dependency from version 42.1.0 to 47.0.3 and refactors multiple SWC plugin files to handle string conversions using lossy UTF-8 representations, including updates to JSX helpers with Wtf8-based string processing and public API changes.

Changes

Cohort / File(s) Summary
Dependency Updates
.changeset/honest-pugs-invent.md, Cargo.toml
New changeset declaring patch bump for @lynx-js/react; swc_core upgraded from 42.1.0 to 47.0.3
Lossy String Conversion Refactoring
packages/react/transform/crates/swc_plugin_compat/lib.rs, packages/react/transform/crates/swc_plugin_css_scope/lib.rs, packages/react/transform/crates/swc_plugin_directive_dce/lib.rs, packages/react/transform/crates/swc_plugin_shake/lib.rs, packages/react/transform/crates/swc_plugin_snapshot/slot_marker.rs, packages/react/transform/crates/swc_plugin_worklet/lib.rs, packages/react/transform/src/swc_plugin_extract_str/mod.rs, packages/react/transform/src/swc_plugin_refresh/mod.rs
Replaced string conversions with to_string_lossy() to handle non-UTF8 content gracefully across import source matching, CSS detection, directive handling, and string literal processing
Cow-based String Normalization
packages/react/transform/crates/swc_plugin_dynamic_import/lib.rs, packages/react/transform/crates/swc_plugin_worklet/extract_ident.rs
Updated return types and property name comparisons to use Cow<'_, str> for uniform handling of Ident and Str variants
Import Alias Additions
packages/react/transform/crates/swc_plugin_list/lib.rs, packages/react/transform/crates/swc_plugin_worklet/gen_stmt.rs
Added use swc_core::atoms as swc_atoms; import alias for internal module organization
JSX Snapshot Plugin Restructuring
packages/react/transform/crates/swc_plugin_snapshot/lib.rs, packages/react/transform/crates/swc_plugin_snapshot/attr_name.rs, packages/react/transform/crates/swc_plugin_text/lib.rs
Introduced bool_jsx_attr() helper, updated attribute value construction, and refactored string handling using lossy conversions for robust tag comparisons
Shared JSX Helpers Modernization
packages/react/transform/crates/swc_plugins_shared/jsx_helpers.rs, packages/react/transform/crates/swc_plugins_shared/utils.rs
Public API change: transform_jsx_attr_str() signature updated from (v: &str) -> String to (v: &Wtf8) -> Wtf8Buf; integrated Wtf8/Wtf8Buf handling throughout; updated string conversions in multiple paths to use lossy representations
Dependency Configuration
packages/react/transform/swc-plugin-reactlynx-compat/Cargo.toml
Removed explicit default-features = false from serde_json dependency, enabling default feature set

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Areas requiring extra attention:

  • Public API changes in jsx_helpers.rs — The signature change for transform_jsx_attr_str() from &str -> String to &Wtf8 -> Wtf8Buf requires verification that all callers have been properly updated and that Wtf8 semantics are correctly implemented
  • swc_core 47.0.3 compatibility — Verify that the upgrade from 42.1.0 to 47.0.3 does not introduce breaking changes or behavioral differences in AST handling across all plugins
  • Lossy UTF-8 conversions — Review patterns of to_string_lossy() usage to ensure non-UTF8 sequences are handled correctly in edge cases and that comparisons remain semantically valid

Possibly related PRs

Suggested labels

framework:React

Suggested reviewers

  • gaoachao
  • PupilTong

Poem

🐰 A hop through strings both old and new,
Lossy conversions, tried and true,
UTF-8 handling, graceful and kind,
Wtf8 buffers, peace of mind!

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: bumping the swc_core dependency to version 47, which is the primary objective of this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 Nov 5, 2025

@codspeed-hq
Copy link

codspeed-hq bot commented Nov 5, 2025

CodSpeed Performance Report

Merging #1916 will improve performances by 6.15%

Comparing colinaaa:colin/1105/swc-47 (4f4b1eb) with main (04f2c39)

Summary

⚡ 1 improvement
✅ 61 untouched
⏩ 3 skipped1

Benchmarks breakdown

Benchmark BASE HEAD Change
basic-performance-small-css 7.3 ms 6.9 ms +6.15%

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.

@relativeci
Copy link

relativeci bot commented Nov 5, 2025

React Example

#6114 Bundle Size — 237.45KiB (0%).

4f4b1eb(current) vs 04f2c39 main#6104(baseline)

Bundle metrics  no changes
                 Current
#6114
     Baseline
#6104
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.77% 46.77%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#6114
     Baseline
#6104
No change  IMG 145.76KiB 145.76KiB
No change  Other 91.69KiB 91.69KiB

Bundle analysis reportBranch colinaaa:colin/1105/swc-47Project dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link

relativeci bot commented Nov 5, 2025

Web Explorer

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

4f4b1eb(current) vs 04f2c39 main#6100(baseline)

Bundle metrics  Change 1 change
                 Current
#6110
     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
#6110
     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 colinaaa:colin/1105/swc-47Project dashboard


Generated by RelativeCIDocumentationReport issue

@colinaaa colinaaa marked this pull request as ready for review November 5, 2025 03:13
@colinaaa colinaaa requested a review from gaoachao as a code owner November 5, 2025 03:13
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 (1)
packages/react/transform/crates/swc_plugin_worklet/extract_ident.rs (1)

213-217: Consider caching lossy conversions to avoid repeated allocations.

The comparison at line 217 calls to_string_lossy() inside the iterator for each Str property, potentially allocating a Cow::Owned string on every iteration when unpaired surrogates are present. While property arrays are typically small, this could be optimized.

One approach is to match on both the input name and iterated property key simultaneously to avoid repeated conversions:

     props
       .iter_mut()
       .find(|prop| match prop.as_prop().unwrap().deref() {
         Prop::Shorthand(sh) if name.is_ident() => {
           let ident = name.as_ident().unwrap();
 
           // We create a tmp Ident with the same `ctxt`
           sh.eq_ignore_span(&Ident::new(ident.sym.clone(), ident.span, sh.ctxt))
         }
-        Prop::KeyValue(KeyValueProp {
-          key: PropName::Ident(id),
-          ..
-        }) => id.sym.as_ref() == name_str,
-        Prop::KeyValue(KeyValueProp {
-          key: PropName::Str(str),
-          ..
-        }) => str.value.to_string_lossy().as_ref() == name_str,
+        Prop::KeyValue(kv) => match (&kv.key, name) {
+          (PropName::Ident(id), PropName::Ident(name_id)) => id.sym == name_id.sym,
+          (PropName::Ident(id), PropName::Str(name_str)) => 
+            id.sym.as_ref() == name_str.value.to_string_lossy().as_ref(),
+          (PropName::Str(str), PropName::Ident(name_id)) => 
+            str.value.to_string_lossy().as_ref() == name_id.sym.as_ref(),
+          (PropName::Str(str), PropName::Str(name_str)) => str.value == name_str.value,
+          _ => false,
+        },
         _ => false,
       })

Alternatively, if the current structure is preferred for readability, the performance impact is likely negligible for typical worklet use cases.

📜 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 04f2c39 and 4f4b1eb.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (20)
  • .changeset/honest-pugs-invent.md (1 hunks)
  • Cargo.toml (1 hunks)
  • packages/react/transform/crates/swc_plugin_compat/lib.rs (2 hunks)
  • packages/react/transform/crates/swc_plugin_css_scope/lib.rs (1 hunks)
  • packages/react/transform/crates/swc_plugin_directive_dce/lib.rs (1 hunks)
  • packages/react/transform/crates/swc_plugin_dynamic_import/lib.rs (2 hunks)
  • packages/react/transform/crates/swc_plugin_list/lib.rs (1 hunks)
  • packages/react/transform/crates/swc_plugin_shake/lib.rs (2 hunks)
  • packages/react/transform/crates/swc_plugin_snapshot/attr_name.rs (1 hunks)
  • packages/react/transform/crates/swc_plugin_snapshot/lib.rs (12 hunks)
  • packages/react/transform/crates/swc_plugin_snapshot/slot_marker.rs (1 hunks)
  • packages/react/transform/crates/swc_plugin_text/lib.rs (1 hunks)
  • packages/react/transform/crates/swc_plugin_worklet/extract_ident.rs (3 hunks)
  • packages/react/transform/crates/swc_plugin_worklet/gen_stmt.rs (1 hunks)
  • packages/react/transform/crates/swc_plugin_worklet/lib.rs (1 hunks)
  • packages/react/transform/crates/swc_plugins_shared/jsx_helpers.rs (8 hunks)
  • packages/react/transform/crates/swc_plugins_shared/utils.rs (3 hunks)
  • packages/react/transform/src/swc_plugin_extract_str/mod.rs (2 hunks)
  • packages/react/transform/src/swc_plugin_refresh/mod.rs (4 hunks)
  • packages/react/transform/swc-plugin-reactlynx-compat/Cargo.toml (1 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/honest-pugs-invent.md
🧠 Learnings (14)
📚 Learning: 2025-09-18T04:43:54.426Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 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 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_worklet/lib.rs
  • packages/react/transform/swc-plugin-reactlynx-compat/Cargo.toml
  • packages/react/transform/crates/swc_plugin_text/lib.rs
  • packages/react/transform/crates/swc_plugin_list/lib.rs
  • packages/react/transform/crates/swc_plugin_compat/lib.rs
  • packages/react/transform/src/swc_plugin_refresh/mod.rs
  • packages/react/transform/crates/swc_plugin_snapshot/lib.rs
  • packages/react/transform/crates/swc_plugin_snapshot/slot_marker.rs
  • packages/react/transform/crates/swc_plugin_worklet/gen_stmt.rs
  • packages/react/transform/crates/swc_plugins_shared/jsx_helpers.rs
📚 Learning: 2025-09-10T11:42:36.855Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 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_worklet/lib.rs
  • packages/react/transform/swc-plugin-reactlynx-compat/Cargo.toml
  • packages/react/transform/crates/swc_plugin_list/lib.rs
  • packages/react/transform/crates/swc_plugin_compat/lib.rs
  • packages/react/transform/src/swc_plugin_refresh/mod.rs
  • packages/react/transform/crates/swc_plugin_shake/lib.rs
  • Cargo.toml
  • packages/react/transform/crates/swc_plugin_worklet/gen_stmt.rs
  • packages/react/transform/crates/swc_plugins_shared/jsx_helpers.rs
  • packages/react/transform/crates/swc_plugin_dynamic_import/lib.rs
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 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:

  • packages/react/transform/swc-plugin-reactlynx-compat/Cargo.toml
  • .changeset/honest-pugs-invent.md
📚 Learning: 2025-10-29T10:28:27.519Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1899
File: packages/react/transform/crates/swc_plugin_snapshot/tests/__swc_snapshots__/lib.rs/should_static_extract_dynamic_inline_style.js:20-24
Timestamp: 2025-10-29T10:28:27.519Z
Learning: Files inside packages/react/transform/crates/swc_plugin_snapshot/tests/__swc_snapshots__/ are auto-generated test snapshot files and should not be manually updated. Any issues with the generated code should be addressed in the code generator/transform logic, not in the snapshots themselves.

Applied to files:

  • packages/react/transform/swc-plugin-reactlynx-compat/Cargo.toml
  • packages/react/transform/crates/swc_plugin_text/lib.rs
  • packages/react/transform/crates/swc_plugin_list/lib.rs
  • packages/react/transform/crates/swc_plugin_compat/lib.rs
  • packages/react/transform/src/swc_plugin_refresh/mod.rs
  • packages/react/transform/crates/swc_plugin_snapshot/lib.rs
  • packages/react/transform/crates/swc_plugin_shake/lib.rs
  • packages/react/transform/crates/swc_plugin_snapshot/slot_marker.rs
  • packages/react/transform/crates/swc_plugin_worklet/gen_stmt.rs
  • packages/react/transform/crates/swc_plugins_shared/jsx_helpers.rs
📚 Learning: 2025-09-18T04:43:54.426Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 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:

  • packages/react/transform/swc-plugin-reactlynx-compat/Cargo.toml
  • .changeset/honest-pugs-invent.md
  • packages/react/transform/crates/swc_plugin_compat/lib.rs
  • packages/react/transform/crates/swc_plugin_snapshot/lib.rs
  • packages/react/transform/crates/swc_plugin_snapshot/slot_marker.rs
  • packages/react/transform/crates/swc_plugins_shared/jsx_helpers.rs
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 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:

  • packages/react/transform/swc-plugin-reactlynx-compat/Cargo.toml
  • .changeset/honest-pugs-invent.md
📚 Learning: 2025-08-19T11:25:36.127Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 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:

  • packages/react/transform/swc-plugin-reactlynx-compat/Cargo.toml
  • .changeset/honest-pugs-invent.md
📚 Learning: 2025-08-07T04:00:59.645Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 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/honest-pugs-invent.md
📚 Learning: 2025-07-22T09:23:07.797Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:23:07.797Z
Learning: In the lynx-family/lynx-stack repository, changesets are only required for meaningful changes to end-users such as bugfixes and features. Internal/development changes like chores, refactoring, or removing debug info do not need changeset entries.

Applied to files:

  • .changeset/honest-pugs-invent.md
📚 Learning: 2025-07-22T09:26:16.722Z
Learnt from: colinaaa
Repo: lynx-family/lynx-stack PR: 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/honest-pugs-invent.md
📚 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/transform/crates/swc_plugin_text/lib.rs
  • packages/react/transform/crates/swc_plugin_compat/lib.rs
  • packages/react/transform/crates/swc_plugin_snapshot/lib.rs
  • packages/react/transform/crates/swc_plugin_snapshot/slot_marker.rs
  • packages/react/transform/crates/swc_plugins_shared/jsx_helpers.rs
📚 Learning: 2025-08-13T09:20:00.936Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1502
File: packages/react/testing-library/types/entry.d.ts:71-71
Timestamp: 2025-08-13T09:20:00.936Z
Learning: In lynx-js/react testing library, wrapper components must have children as a required prop because they are always called with `h(WrapperComponent, null, innerElement)` where innerElement is passed as children. The type `React.JSXElementConstructor<{ children: React.ReactNode }>` correctly requires children to be mandatory.

Applied to files:

  • packages/react/transform/crates/swc_plugin_snapshot/lib.rs
📚 Learning: 2025-11-04T10:15:14.916Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1899
File: packages/react/runtime/__test__/snapshotPatch.test.jsx:725-749
Timestamp: 2025-11-04T10:15:14.916Z
Learning: In packages/react/runtime/src/snapshot.ts, the snapshotCreatorMap type signature uses `Record<string, (uniqId: string) => string>` (returning string) rather than void for backward compatibility. Old lazy bundles still use the pattern `const snapshot_xxx = createSnapshot(...)` directly, which requires createSnapshot to return a value. The snapshotCreatorMap creators that wrap createSnapshot calls must maintain the same return type to support these legacy bundles.

Applied to files:

  • packages/react/transform/crates/swc_plugin_snapshot/slot_marker.rs
📚 Learning: 2025-09-23T08:53:56.927Z
Learnt from: upupming
Repo: lynx-family/lynx-stack PR: 1670
File: packages/webpack/css-extract-webpack-plugin/src/loader.ts:244-251
Timestamp: 2025-09-23T08:53:56.927Z
Learning: In webpack CSS extraction plugins, when storing per-module dependencies in a compiler-scoped map like cssModuleId2Deps, the map should not be reset at compilation start because in incremental compilation (watch mode/HMR), only changed files pass through the loader. Unchanged modules need their dependency information to persist between compilations so the plugin can access all modules' dependencies when generating CSS output.

Applied to files:

  • packages/react/transform/crates/swc_plugin_css_scope/lib.rs
🧬 Code graph analysis (5)
packages/react/transform/crates/swc_plugin_worklet/lib.rs (1)
packages/react/transform/crates/swc_plugin_worklet/worklet_type.rs (1)
  • from_directive (8-16)
packages/react/transform/crates/swc_plugin_compat/lib.rs (1)
packages/react/transform/crates/swc_plugin_css_scope/lib.rs (1)
  • n (129-139)
packages/react/transform/crates/swc_plugin_snapshot/lib.rs (2)
packages/react/transform/crates/swc_plugin_list/lib.rs (1)
  • new (27-33)
packages/react/transform/crates/swc_plugins_shared/jsx_helpers.rs (1)
  • transform_jsx_attr_str (342-393)
packages/react/transform/crates/swc_plugin_shake/lib.rs (1)
packages/react/transform/crates/swc_plugin_css_scope/lib.rs (1)
  • n (129-139)
packages/react/transform/crates/swc_plugin_worklet/extract_ident.rs (1)
packages/react/transform/src/lib.rs (1)
  • max (730-732)
🔇 Additional comments (31)
packages/react/transform/crates/swc_plugin_worklet/lib.rs (1)

461-463: LGTM! Correct migration to swc_core v47.

The change correctly adapts to the Atom → Wtf8Atom breaking change by using to_string_lossy().into_owned(). Since worklet directives are ASCII strings ("main thread", "main-thread", "use worklet"), the lossy conversion will never lose information in practice, and any invalid UTF-8 sequences would correctly fail to match the expected directives.

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

153-159: LGTM: Correct adaptation to swc_core v47 Wtf8Atom API.

The change from to_string() to to_string_lossy() is necessary for the swc_core v47 upgrade. The comparison logic using any() with exact equality is correct and more precise than a substring match. The lossy conversion replaces unpaired surrogates with U+FFFD, which is appropriate here since package names in practice consist of valid UTF-8 strings.


253-253: LGTM: Correct handling of Wtf8Atom for computed properties.

The change to to_string_lossy().into_owned() is necessary for swc_core v47. The into_owned() call correctly converts the Cow<str> to String as required by the ref_names tuple type. The lossy conversion is appropriate for property names.


293-572: Manually verify that all tests pass with the swc_core v47 upgrade.

The sandbox environment does not support running cargo tests. Please execute the following command locally to verify the test suite passes with the new Wtf8Atom API and confirm no regressions were introduced:

cd packages/react/transform/crates/swc_plugin_shake && cargo test --lib

Ensure all 12 test cases pass, particularly:

  • should_remove_test and related removal cases
  • should_not_remove_in_scope_id (scoping verification)
  • should_keep_access_inside_class_property_iife (property access edge cases)
packages/react/transform/crates/swc_plugin_worklet/extract_ident.rs (2)

7-7: LGTM!

The addition of Cow import is appropriate for the new string normalization logic necessitated by the swc_core v47 upgrade.


195-200: Insufficient evidence to confirm or resolve the surrogate pair concern—manual verification needed.

The search found no surrogate pair handling or U+FFFD edge cases in the codebase. While this doesn't prove the concern is unfounded (absence of evidence is not evidence of absence), the codebase appears to silently accept this edge case without explicit protection.

Verify manually:

  • Whether worklet transformations encounter dynamically-generated property names with unpaired surrogates in practice
  • Whether lossy surrogate-to-U+FFFD conversion could cause unintended property name collisions in your use cases
packages/react/transform/crates/swc_plugin_directive_dce/lib.rs (1)

67-67: LGTM! Correct adaptation to swc_core v47.

The change from to_string().as_str() to to_string_lossy().as_ref() correctly handles the Wtf8Atom type. For directive string matching, lossy conversion is appropriate since valid directives should be valid UTF-8.

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

22-22: LGTM! Consistent string conversion for JSON serialization.

All three conversions correctly use to_string_lossy().into_owned() to produce owned String values required by serde_json::Value::String. The lossy conversion is appropriate for JSON serialization.

Also applies to: 40-40, 54-54

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

152-161: LGTM! Efficient string handling for CSS imports.

The code correctly computes the lossy string representation once and reuses it for both the regex check and the formatted output. This is an efficient pattern that avoids redundant conversions.

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

517-567: LGTM! Proper package import handling with deprecation warnings.

The code correctly extracts the import source once using to_string_lossy().into_owned() and reuses it for both package checks and warning messages. The approach is consistent and handles the swc_core v47 API correctly.

packages/react/transform/src/swc_plugin_extract_str/mod.rs (1)

150-175: LGTM! Efficient string extraction with consistent handling.

The code correctly computes the lossy string once and reuses it for length checks, position lookups, and storage. The pattern is efficient and handles both the JavaScript and Lepus extraction paths consistently.

packages/react/transform/src/swc_plugin_refresh/mod.rs (1)

1-4: LGTM! Excellent use of Cow for performance.

The code makes smart use of Cow<'_, str> to minimize allocations:

  • Ident branch uses Cow::Borrowed to avoid allocation
  • Str branch uses to_string_lossy() which returns Cow and only allocates if lossy conversion is needed
  • Comparisons use .as_ref() to borrow from the Cow
  • .into_owned() is only used when the string must outlive the Cow

This is an efficient pattern that balances correctness with performance.

Also applies to: 83-83, 106-110, 223-223

packages/react/transform/crates/swc_plugins_shared/jsx_helpers.rs (4)

6-6: LGTM! Correct type conversions for Wtf8-based strings.

The imports and conversions correctly adapt to swc_core v47's Wtf8-based string types. The .into() calls allow the compiler to perform the necessary type conversions.

Also applies to: 26-26, 114-114, 181-181


86-93: LGTM! Proper JSX attribute string transformation.

The new branch correctly handles JSXAttrValue::Str by transforming it through transform_jsx_attr_str before wrapping as a Lit::Str. This ensures JSX attribute strings are properly escaped and normalized.


218-218: LGTM! Consistent string comparisons with lossy conversion.

The comparisons correctly use to_string_lossy().as_ref() to handle Wtf8Atom values. For tag name matching ("page", "list", "list-item"), lossy conversion is appropriate since valid element names should be valid UTF-8.

Also applies to: 251-251, 258-258


342-393: Function is tested through comprehensive snapshot test suite—no additional verification needed.

The transform_jsx_attr_str function is exercised through the extensive snapshot tests in swc_plugin_snapshot/tests. Since the function is called during JSX attribute processing (__SetAttribute, __AddDataset, __SetInlineStyles, __SetClasses, __SetID), all snapshot tests that include JSX elements with attributes verify the Wtf8-based implementation indirectly. The transformation is validated as part of the normal JSX transformation pipeline.

packages/react/transform/crates/swc_plugin_snapshot/attr_name.rs (1)

49-49: LGTM! Correct string conversion for attribute name handling.

The change from as_ref().to_string() to to_string_lossy().into_owned() correctly adapts to swc_core v47. Using into_owned() is appropriate here since the string is passed to Self::from(name) where it may be stored in various AttrName variants.

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

18-23: Correct implementation of Wtf8Atom migration.

The change to use to_string_lossy() correctly handles the migration from Atom to Wtf8Atom. Since INTERNAL_SLOT_STR is an ASCII constant, the lossy conversion (which replaces unpaired surrogates with U+FFFD) has no practical impact on correctness.

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

124-132: Good refactor for boolean JSX attributes.

The new bool_jsx_attr helper eliminates code duplication and ensures consistent creation of boolean JSX attribute values throughout the codebase.


289-360: Correct implementation of tag name comparison with Wtf8Atom.

The use of to_string_lossy() for tag name extraction and comparison is the correct approach for the Wtf8Atom migration. Since tag names are standardized JSX identifiers (ASCII), the lossy conversion has no adverse effects.


551-557: Consistent and correct attribute value transformation.

The pattern of using transform_jsx_attr_str() to process Wtf8 string values while preserving span information is correctly applied across all attribute types (Attr, Dataset, Style, Class, ID). This ensures proper handling of special characters and maintains source location tracking.

Also applies to: 606-612, 651-657, 704-709, 744-749


1107-1156: Proper tag comparison in JSX element visitor.

The tag name extraction using to_string_lossy() followed by string comparison correctly implements the Wtf8Atom migration pattern. The special handling for "wrapper", "page", and "component" tags is appropriate.

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

3-3: LGTM: Cow import added for new return type.

The addition of Cow to the imports is necessary for the updated function signature.


71-79: LGTM: Correct migration to Wtf8Atom-based string handling.

The function signature and implementation have been appropriately updated to use Cow<'_, str> with to_string_lossy(), which is the standard migration path for swc_core v47. All downstream usages at lines 171–173 (.starts_with()) and 196 (format!) remain compatible via Deref and Display traits. This pattern is consistently used across the codebase (swc_plugins_shared, swc_plugin_worklet, swc_plugin_snapshot, and other plugins), confirming it is the approved approach for Wtf8Atom conversion.

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

31-35: LGTM! Correct adaptation to new SWC AST structure.

The change from Lit::Str wrapper to direct Str correctly adapts to the Flexible AST changes in swc_core v47. The structure and conversion logic are appropriate.


27-27: Verify jsx_text_to_str implementation handles Wtf8Atom correctly.

The function at line 138-168 in packages/react/transform/crates/swc_plugins_shared/jsx_helpers.rs calls .replace() and .lines() directly on &Atom without explicit to_string_lossy() conversion. However, other code in the same file (lines 218, 251, 258) uses the .value.to_string_lossy() pattern for safe Wtf8Atom handling.

Confirm whether the current implementation correctly handles surrogate code points in Wtf8Atom, or if it needs to use .to_string_lossy() like the rest of the codebase.

.changeset/honest-pugs-invent.md (1)

1-5: Verify that the public API remains unchanged.

The changeset correctly documents the dependency bump. However, since swc_core v47 introduces breaking changes (Atom → Wtf8Atom, flexible AST), ensure these internal changes don't affect the public API of @lynx-js/react. If the public API changes, this should be marked as a major or minor release instead of a patch.

Based on learnings and coding guidelines.

packages/react/transform/swc-plugin-reactlynx-compat/Cargo.toml (1)

11-11: Clarify the reason for enabling default features.

The default-features = false flag has been removed from the serde_json dependency, which will now enable all default features (including std). This change could increase binary size and alter behavior.

Please clarify why this change was necessary for swc_core v47 compatibility. Was it to:

  1. Fix compilation errors?
  2. Enable required std features?
  3. Align with swc_core v47's requirements?

Based on learnings regarding derive feature requirements in this codebase.

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

1-1: Remove the unused swc_atoms import.

The import alias use swc_core::atoms as swc_atoms; at line 1 is unused throughout the file and should be removed. A full file scan confirms no references to swc_atoms in any code paths, macros, re-exports, or type signatures.

⛔ Skipped due to learnings
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 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 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.
packages/react/transform/crates/swc_plugin_worklet/gen_stmt.rs (1)

7-7: Remove unused import alias on line 7.

The swc_atoms alias is imported but never used anywhere in the swc_plugin_worklet crate. Remove the unused import:

use swc_core::atoms as swc_atoms;
⛔ Skipped due to learnings
Learnt from: gaoachao
Repo: lynx-family/lynx-stack PR: 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 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.
Cargo.toml (1)

30-30: Verify swc_core v47 breaking changes are properly addressed in compilation.

Version consistency across all workspace crates is correct (all pin to 47.0.3), and swc_atoms imports follow the v47 pattern. However, the PR description mentions an "Atom → Wtf8Atom" breaking change, yet the codebase still uses Atom::from() in packages/react/transform/src/swc_plugin_refresh/mod.rs with no Wtf8Atom references anywhere.

Verify that the codebase compiles successfully with swc_core v47 and confirm whether the Atom API remains available or if migration to Wtf8Atom is required. RustDoc is available at https://rustdoc.swc.rs/swc_core/ for reference.

@gaoachao gaoachao merged commit ffd193b into lynx-family:main Nov 6, 2025
50 of 51 checks passed
colinaaa pushed a commit that referenced this pull request Nov 9, 2025
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @lynx-js/[email protected]

### Patch Changes

- During hydration, replace update with insert + remove for same-type
`<list-item />` with different `item-key` so the Lynx Engine detects
changes. ([#1598](#1598))

    ```html
    Hydrate List B into List A: List A:
    <list>
      <list-item item-key="a">hello</list-item>
      <list-item item-key="a">world</list-item>
    </list>

    List B:
    <list>
      <list-item item-key="a1">hello</list-item>
      <list-item item-key="a2">world</list-item>
    </list>
    ```

Previously this case was hydrated as an update; it is now emitted as
insert + remove to ensure SDK detection.

- Bump `swc_core` v47.
([#1916](#1916))

- Pass sourcemap generated by rspack to swc transformer.
([#1910](#1910))

- When engineVersion is greater than or equal to 3.1, use
`__SetAttribute` to set text attribute for text node instead of creating
a raw text node.
([#1880](#1880))

- Add profile for list `update-list-info`.
([#1480](#1480))

- Support testing React Compiler in testing library. Enable React
Compiler by setting the `experimental_enableReactCompiler` option of
`createVitestConfig` to `true`.
([#1269](#1269))

    ```js
    import { defineConfig, mergeConfig } from "vitest/config";
import { createVitestConfig } from
"@lynx-js/react/testing-library/vitest-config";

    const defaultConfig = await createVitestConfig({
      runtimePkgName: "@lynx-js/react",
      experimental_enableReactCompiler: true,
    });

    export default mergeConfig(defaultConfig, config);
    ```

## @lynx-js/[email protected]

### Patch Changes

-   Updated dependencies \[]:
    -   @lynx-js/[email protected]

## @lynx-js/[email protected]

### Patch Changes

- fix: print out the output chunk urls
([#1921](#1921))

## @lynx-js/[email protected]

### Patch Changes

- When engineVersion is greater than or equal to 3.1, use
`__SetAttribute` to set text attribute for text node instead of creating
a raw text node.
([#1880](#1880))

- Add `react-compiler-runtime` to `resolve.dedupe`.
([#1269](#1269))

With this change you can setup [React
Compiler](https://react.dev/learn/react-compiler) for ReactLynx by
`pluginBabel`:

    ```js
    import { defineConfig } from "@lynx-js/rspeedy";
    import { pluginBabel } from "@rsbuild/plugin-babel";

    export default defineConfig({
      plugins: [
        pluginBabel({
          include: /\.(?:jsx|tsx)$/,
          babelLoaderOptions(opts) {
            opts.plugins?.unshift([
              "babel-plugin-react-compiler",
// See https://react.dev/reference/react-compiler/configuration for
config
              {
                // ReactLynx only supports target to version 17
                target: "17",
              },
            ]);
          },
        }),
      ],
    });
    ```

- Updated dependencies
\[[`e7d186a`](e7d186a),
[`0d7a4c3`](0d7a4c3)]:
    -   @lynx-js/[email protected]
    -   @lynx-js/[email protected]
    -   @lynx-js/[email protected]
    -   @lynx-js/[email protected]

## @lynx-js/[email protected]

### Patch Changes

- feat: add \_\_GetSourceMapRelease API for nativeApp.
([#1923](#1923))

-   Updated dependencies \[]:
    -   @lynx-js/[email protected]

## @lynx-js/[email protected]

### Patch Changes

- Updated dependencies
\[[`fece7d0`](fece7d0),
[`e1db63f`](e1db63f),
[`ebc1a60`](ebc1a60)]:
    -   @lynx-js/[email protected]
    -   @lynx-js/[email protected]
    -   @lynx-js/[email protected]
    -   @lynx-js/[email protected]

## @lynx-js/[email protected]

### Patch Changes

- fix: define x-foldview-slot-drag-ng typo.
([#1915](#1915))

- feat: 1. Added support for the list `estimated-main-axis-size-px`
property; the width and height of `list-item` are no longer required.
([#1911](#1911))

2. Fixed an issue where the list `lower-threshold-item-count` event
would not trigger when using a horizontal layout under a waterfall
layout.

3. Fixed an issue where calling the list `autoScroll` method in
`useEffect` might not scroll.

4. Fixed an issue where the `scrolltolower` event might not be triggered
in waterfall, because the lower styles was not updated in
`registerEventEnableStatusChangeHandler`.

-   Updated dependencies \[]:
    -   @lynx-js/[email protected]

## @lynx-js/[email protected]

### Patch Changes

- fix: define x-foldview-slot-drag-ng typo.
([#1915](#1915))

## @lynx-js/[email protected]

### Patch Changes

- feat: update @lynx-js/web-elements to 0.8.10
([#1914](#1914))

## @lynx-js/[email protected]

### Patch Changes

- fix: The `e.detail` in the `bindtap` callback needs to correctly
include `x` and `y`.
([#1913](#1913))

- Updated dependencies
\[[`ebc1a60`](ebc1a60)]:
    -   @lynx-js/[email protected]
    -   @lynx-js/[email protected]

## @lynx-js/[email protected]

### Patch Changes

- fix: `this` may be undefined in Card().
([#1922](#1922))

- feat: add \_\_GetSourceMapRelease API for nativeApp.
([#1923](#1923))

- Updated dependencies
\[[`fece7d0`](fece7d0),
[`ebc1a60`](ebc1a60)]:
    -   @lynx-js/[email protected]
    -   @lynx-js/[email protected]
    -   @lynx-js/[email protected]

## @lynx-js/[email protected]

### Patch Changes

- Pass sourcemap generated by rspack to swc transformer.
([#1910](#1910))

- When engineVersion is greater than or equal to 3.1, use
`__SetAttribute` to set text attribute for text node instead of creating
a raw text node.
([#1880](#1880))

## [email protected]



## @lynx-js/[email protected]



## [email protected]



## @lynx-js/[email protected]



## @lynx-js/[email protected]



## @lynx-js/[email protected]



## @lynx-js/[email protected]



## @lynx-js/[email protected]

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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