-
Notifications
You must be signed in to change notification settings - Fork 111
feat: introduce swc-plugin-reactlynx-compat
#1824
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
🦋 Changeset detectedLatest commit: 57c0baa The changes in this PR will be included in the next version bump. This PR includes changesets to release 0 packagesWhen 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 |
📝 WalkthroughWalkthroughAdds lint ignore patterns; adds serde as a dependency and derives Deserialize for several compat types; implements Deserialize for TransformTarget with tests; adds a new swc-plugin-reactlynx-compat plugin entry point, TypeScript config declarations, Turbo build config, and switches some crate dependencies to use the local compat crate. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labelsframework:React Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches🧪 Generate unit tests
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
🧰 Additional context used🧠 Learnings (5)📓 Common learnings📚 Learning: 2025-09-12T09:43:04.847ZApplied to files:
📚 Learning: 2025-08-19T11:25:36.127ZApplied to files:
📚 Learning: 2025-09-18T04:43:54.426ZApplied to files:
📚 Learning: 2025-09-10T11:42:36.855ZApplied to files:
⏰ 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)
🔇 Additional comments (2)
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. Comment |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
CodSpeed Performance ReportMerging #1824 will degrade performances by 7.53%Comparing Summary
Benchmarks breakdown
Footnotes
|
Web Explorer#5515 Bundle Size — 365.44KiB (0%).57c0baa(current) vs 9ab108f main#5513(baseline) Bundle metrics
Bundle size by type
|
| Current #5515 |
Baseline #5513 |
|
|---|---|---|
239.42KiB |
239.42KiB |
|
94.02KiB |
94.02KiB |
|
32KiB |
32KiB |
Bundle analysis report Branch feat/introduce-swc-plugin-react-... Project dashboard
Generated by RelativeCI Documentation Report issue
React Example#5520 Bundle Size — 237.56KiB (0%).57c0baa(current) vs 9ab108f main#5518(baseline) Bundle metrics
|
| Current #5520 |
Baseline #5518 |
|
|---|---|---|
0B |
0B |
|
0B |
0B |
|
0% |
0% |
|
0 |
0 |
|
4 |
4 |
|
166 |
166 |
|
68 |
68 |
|
46.81% |
46.81% |
|
2 |
2 |
|
0 |
0 |
Bundle size by type no changes
| Current #5520 |
Baseline #5518 |
|
|---|---|---|
145.76KiB |
145.76KiB |
|
91.8KiB |
91.8KiB |
Bundle analysis report Branch feat/introduce-swc-plugin-react-... Project dashboard
Generated by RelativeCI Documentation Report issue
There was a problem hiding this 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 (4)
packages/react/transform/crates/swc_plugin_compat/lib.rs (4)
29-33: Untyped union deserialization will fail without#[serde(untagged)].Config expects raw values (e.g.,
addComponentElement: trueor{ compilerOnly: true }). Without untagged, serde requires{ "A": true }/{ "B": { ... } }.Apply:
-#[derive(Deserialize, Debug, Clone, PartialEq)] +#[derive(Deserialize, Debug, Clone, PartialEq)] +#[serde(untagged)] pub enum Either<A, B> {
66-71: CamelCase config keys won’t map to Rust fields. Add rename strategy.TS config uses
themeExpr; Rust field istheme_expr. Add rename_all.-#[derive(Deserialize, Clone, Debug)] +#[derive(Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] pub struct DarkModeConfig {
75-99: CamelCase config keys won’t map to Rust fields. Add rename strategy.
compilerOnly→compiler_only.-#[derive(Deserialize, Clone, Debug)] +#[derive(Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] pub struct AddComponentElementConfig {
103-107: Add serde camelCase + defaults to CompatVisitorConfig (TransformTarget already Deserialize)
- TS keys use camelCase (componentsPkg, oldRuntimePkg, …); struct lacks #[serde(rename_all = "camelCase")].
- Many fields are non-optional; add serde defaults (per-field #[serde(default = "...")] or #[serde(default)] + Default impl) so partial plugin configs deserialize.
- TransformTarget already implements Deserialize (packages/react/transform/crates/swc_plugins_shared/target.rs).
Proposed fixes:
-#[derive(Deserialize, Clone, Debug)] +#[derive(Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] pub struct CompatVisitorConfig { /// @internal - pub target: TransformTarget, + #[serde(default = "default_target")] + pub target: TransformTarget, @@ - pub components_pkg: Vec<String>, + #[serde(default = "default_components_pkg")] + pub components_pkg: Vec<String>, @@ - pub old_runtime_pkg: Vec<String>, + #[serde(default = "default_old_runtime_pkg")] + pub old_runtime_pkg: Vec<String>, @@ - pub new_runtime_pkg: String, + #[serde(default = "default_new_runtime_pkg")] + pub new_runtime_pkg: String, @@ - pub add_component_element: Either<bool, AddComponentElementConfig>, + #[serde(default = "default_add_component_element")] + pub add_component_element: Either<bool, AddComponentElementConfig>,Add these helpers (near the struct):
fn default_target() -> TransformTarget { TransformTarget::LEPUS } fn default_components_pkg() -> Vec<String> { vec!["@lynx-js/react-components".into()] } fn default_old_runtime_pkg() -> Vec<String> { vec!["@lynx-js/react-runtime".into()] } fn default_new_runtime_pkg() -> String { "@lynx-js/react".into() } fn default_add_component_element() -> Either<bool, AddComponentElementConfig> { Either::A(false) }Also applies to: 129-130, 152-153, 175-176, 245-246
🧹 Nitpick comments (6)
packages/react/transform/swc-plugin-reactlynx-compat/turbo.json (1)
1-11: Include Cargo.lock in inputs and consider depending on upstream builds.This tightens cache correctness and typical Turbo DAG semantics.
Apply:
"tasks": { "build": { - "dependsOn": [], - "inputs": [".cargo/**", "src/**/*.rs", "Cargo.toml", "build.js"], + "dependsOn": ["^build"], + "inputs": [".cargo/**", "src/**/*.rs", "Cargo.toml", "Cargo.lock", "build.js"], "outputs": ["swc_plugin_reactlynx_compat.wasm"] } }packages/react/transform/crates/swc_plugins_shared/target.rs (1)
10-25: Manual Deserialize works; consider derive with renames for brevity.You can replace the manual impl with derive and per-variant renames.
-use serde::{Deserialize, Deserializer}; +use serde::Deserialize; @@ -impl<'de> Deserialize<'de> for TransformTarget { - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where - D: Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - match s.as_str() { - "LEPUS" => Ok(TransformTarget::LEPUS), - "JS" => Ok(TransformTarget::JS), - "MIXED" => Ok(TransformTarget::MIXED), - _ => Err(serde::de::Error::custom(format!( - "value `{s}` does not match any variant of TransformTarget" - ))), - } - } -} +#[derive(Deserialize)] +#[serde(rename_all = "UPPERCASE")] +pub enum TransformTarget { + #[serde(rename = "LEPUS")] + LEPUS, + #[serde(rename = "JS")] + JS, + #[serde(rename = "MIXED")] + MIXED, +}If you adopt this, adjust the error assertion in tests to match Serde’s default message.
packages/react/transform/swc-plugin-reactlynx-compat/src/lib.rs (1)
8-15: Avoid silently swallowing config parse errors; pass comments without as_ref().Log parse failures and use metadata.comments directly to match CompatVisitor::new generic better.
pub fn process_transform(program: Program, metadata: TransformPluginProgramMetadata) -> Program { let config_json = metadata.get_transform_plugin_config().unwrap_or_default(); - let config: CompatVisitorConfig = serde_json::from_str(&config_json).unwrap_or_default(); - let comments = metadata.comments.as_ref(); + let config: CompatVisitorConfig = if config_json.is_empty() { + Default::default() + } else { + serde_json::from_str(&config_json).unwrap_or_else(|err| { + eprintln!("[swc-plugin-reactlynx-compat] Failed to parse config: {err}. Falling back to defaults."); + Default::default() + }) + }; + let comments = metadata.comments; program.apply(&mut visit_mut_pass(CompatVisitor::new(config, comments))) }Also ensure this crate depends on serde and serde_json.
packages/react/transform/swc-plugin-reactlynx-compat/index.d.ts (3)
44-48: Remove stray docblock not attached to a declaration.This appears to be orphaned and duplicates prior context.
-/** - * {@inheritdoc CompatVisitorConfig.addComponentElement} - * @public - */ -
12-17: Tighten wording: compilerOnly description.Minor grammar/clarity fix.
- * Whether to only add component element during compilation + * Whether to add the component element only during compilation @@ - * Note that this only take effects on `Component` imported from {@link CompatVisitorConfig.oldRuntimePkg}. + * Note that this only takes effect on `Component` imported from {@link CompatVisitorConfig.oldRuntimePkg}.
186-188: Fix grammar: “take effects” → “takes effect”.- * Note that this only take effects on `Component` imported from {@link CompatVisitorConfig.oldRuntimePkg}. + * Note that this only takes effect on `Component` imported from {@link CompatVisitorConfig.oldRuntimePkg}.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (10)
.changeset/loud-carrots-relate.md(1 hunks)biome.jsonc(1 hunks)eslint.config.js(1 hunks)packages/react/transform/crates/swc_plugin_compat/Cargo.toml(1 hunks)packages/react/transform/crates/swc_plugin_compat/lib.rs(5 hunks)packages/react/transform/crates/swc_plugins_shared/target.rs(1 hunks)packages/react/transform/swc-plugin-reactlynx-compat/Cargo.toml(1 hunks)packages/react/transform/swc-plugin-reactlynx-compat/index.d.ts(1 hunks)packages/react/transform/swc-plugin-reactlynx-compat/src/lib.rs(1 hunks)packages/react/transform/swc-plugin-reactlynx-compat/turbo.json(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/loud-carrots-relate.md
🧠 Learnings (7)
📓 Common learnings
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.
📚 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_plugins_shared/target.rspackages/react/transform/swc-plugin-reactlynx-compat/Cargo.tomlpackages/react/transform/crates/swc_plugin_compat/Cargo.tomlpackages/react/transform/crates/swc_plugin_compat/lib.rspackages/react/transform/swc-plugin-reactlynx-compat/turbo.json
📚 Learning: 2025-07-18T04:27:18.291Z
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1238
File: packages/react/runtime/src/debug/component-stack.ts:70-90
Timestamp: 2025-07-18T04:27:18.291Z
Learning: The component-stack.ts file in packages/react/runtime/src/debug/component-stack.ts is a direct fork from https://github.com/preactjs/preact/blob/main/debug/src/component-stack.js. The team prefers to keep it aligned with the upstream Preact version and may contribute improvements back to Preact in the future.
Applied to files:
biome.jsonc
📚 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:
packages/react/transform/swc-plugin-reactlynx-compat/Cargo.toml
📚 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/swc-plugin-reactlynx-compat/src/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/swc-plugin-reactlynx-compat/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/loud-carrots-relate.md
🧬 Code graph analysis (1)
packages/react/transform/swc-plugin-reactlynx-compat/src/lib.rs (2)
packages/react/transform/swc-plugin-reactlynx-compat/index.d.ts (1)
CompatVisitorConfig(53-323)packages/react/transform/crates/swc_plugin_compat/lib.rs (1)
new(413-425)
🔇 Additional comments (6)
.changeset/loud-carrots-relate.md (1)
1-3: Empty changeset is acceptable here; confirm no user-facing release is needed.This follows the repo practice for internal-only changes. If any npm/crate packages gain new public surface (e.g., new TS declarations shipped), we should include proper bumps instead of an empty changeset.
Do these changes alter any published package’s public API or behavior? If yes, replace this with a non-empty changeset listing affected packages and bump types.
eslint.config.js (1)
69-72: LGTM: broadened ignore to nested index.d.ts files.Matches the Biome change and should reduce noisy lint on generated declarations.
biome.jsonc (1)
37-40: LGTM: Biome ignore aligned with ESLint.Keeps generated nested declarations out of linting.
packages/react/transform/crates/swc_plugin_compat/Cargo.toml (1)
16-16: Ensure serde derive feature is enabled.Types in this crate derive Deserialize; serde must have features = ["derive"] either at workspace level or here.
If not enabled at workspace level, apply:
-serde = { workspace = true } +serde = { workspace = true, features = ["derive"] }packages/react/transform/crates/swc_plugins_shared/target.rs (1)
27-66: Add serde and serde_json to swc_plugins_shared Cargo.tomlAdd serde to [dependencies] and serde_json to [dev-dependencies] in packages/react/transform/crates/swc_plugins_shared/Cargo.toml so tests using serde_json and serde derives compile. If serde is provided via workspace.dependencies, enable the "derive" feature (features = ["derive"]).
packages/react/transform/swc-plugin-reactlynx-compat/Cargo.toml (1)
13-13: Approve: no lingering direct deps found in swc-plugin-reactlynx-compatSearch in packages/react/transform/swc-plugin-reactlynx-compat found no matches for convert_case, once_cell, regex, or rustc-hash — switching to swc_plugin_compat is safe.
swc-plugin-react-lynx-compatswc-plugin-reactlynx-compat
Summary by CodeRabbit
New Features
New Features (Types)
Documentation
Tests
Chores
Checklist