Skip to content

Conversation

@CCherry07
Copy link
Member

@CCherry07 CCherry07 commented Sep 1, 2025

Summary by CodeRabbit

  • New Features

    • Added runtime path configuration in the Worker playground.
    • Worker-produced resources now emit with .mjs extension.
  • Improvements

    • Updated plugins and playgrounds for Farm v2 (beta) compatibility.
    • Improved SVG/icon caching and more stable parsing, codegen and sourcemap behavior.
    • Expanded global component typings in the React Components playground.
  • Breaking Changes

    • Developer-facing plugin APIs and resource/filename behaviors changed; plugin updates may be required.
  • Chores

    • Multiple dependency bumps and Rust toolchain update; package version bumps and changelogs added.

@coderabbitai
Copy link

coderabbitai bot commented Sep 1, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Workspace dependency upgrades and multiple plugin migrations to Farm v2-beta: import path relocations, Arc-wrapped module content for SWC parsing, SWC codegen/sourcemap and Ident SyntaxContext updates, adoption of TransformOutputFileNameParams, SVGR/jsx-runtime adjustments, icons cache switched to bincode, Cargo.toml workspace refactors, playground package bumps, and toolchain update.

Changes

Cohort / File(s) Summary
Workspace deps bump
Cargo.toml
Updates workspace dependency versions to 2.x in top-level workspace dependencies.
Playground package versions
rust-plugins/auto-import/playground-react/package.json, rust-plugins/auto-import/playground-vue/package.json, rust-plugins/react-components/playground/package.json, rust-plugins/wasm/playground/package.json, rust-plugins/worker/playground/package.json
Bumps @farmfe/core and related @farmfe packages to 2.0.0-beta / nightly variants; small playground config addition (runtime.path).
PathFilter / normalize_path import updates
rust-plugins/auto-import/src/lib.rs, rust-plugins/dsv/src/lib.rs, rust-plugins/image/src/lib.rs, rust-plugins/url/src/lib.rs, rust-plugins/strip/src/lib.rs, rust-plugins/react-components/src/lib.rs, rust-plugins/react-components/src/find_local_components.rs, rust-plugins/auto-import/src/parser/scan_dirs_exports.rs, rust-plugins/auto-import/src/parser/scan_exports.rs
Moves imports to farmfe_toolkit::plugin_utils::{path_filter::PathFilter, normalize_path::normalize_path}; usage unchanged.
Parser content Arc migration
rust-plugins/auto-import/src/parser/parse.rs, rust-plugins/react-components/src/find_local_components.rs, rust-plugins/react-components/src/lib.rs, rust-plugins/strip/src/lib.rs
Wraps module content in Arc<String> for parsing, updates parse_module call-sites and result destructuring ({ ast, .. }).
Cargo manifests → workspace = true / dep bumps
rust-plugins/compress/Cargo.toml, rust-plugins/modular-import/Cargo.toml, rust-plugins/wasm/Cargo.toml, rust-plugins/url/Cargo.toml, rust-plugins/icons/Cargo.toml, rust-plugins/worker/Cargo.toml
Switches many farmfe_* crates to workspace = true; bumps rkyv, svgr-rs, xmltree, cached, bincode; adds serde and rustc-hash where needed.
Icons cache → bincode / cache tuple
rust-plugins/icons/src/cache/mod.rs, rust-plugins/icons/src/lib.rs
Replaces serde with bincode (Encode/Decode), stores cached entries as encoded (CacheValue, usize), and unwraps cache_dir when initializing HttpClient.
SVGR / icons JSX runtime config
rust-plugins/svgr/Cargo.toml, rust-plugins/svgr/src/react_compiler.rs, rust-plugins/icons/src/compiler/react.rs, rust-plugins/icons/src/compiler/preact.rs
Upgrades svgr-rs and changes Config.jsx_runtime from Option<JSXRuntime> to direct JSXRuntime; drops explicit expand_props field.
TransformOutputFileNameParams adoption
rust-plugins/url/src/lib.rs, rust-plugins/wasm/src/lib.rs, rust-plugins/worker/src/lib.rs
Replaces multi-arg transform_output_filename(...) calls with single TransformOutputFileNameParams struct parameter and updates imports.
Plugin hook/type and Resource shape changes
rust-plugins/url/src/lib.rs, rust-plugins/compress/src/lib.rs, rust-plugins/worker/src/lib.rs, rust-plugins/compress/Cargo.toml
finalize_resources hook param type changed (PluginFinalizeResourcesHookParamsPluginFinalizeResourcesHookParam); Resource struct gained name_hash, meta, should_transform_output_filename, special_placeholders and removed info; compress plugin updated accordingly.
SWC source-map/codegen migration
rust-plugins/react-components/src/lib.rs, rust-plugins/strip/src/lib.rs
Uses create_swc_source_map, passes Arc<content>, uses swc_ecma_codegen::Config::default() and cm.build_source_map(..., DefaultSourceMapGenConfig) for codegen/sourcemap.
SWC Ident / SyntaxContext additions
rust-plugins/react-components/src/insert_import.rs, rust-plugins/strip/src/lib.rs
Ident::new calls updated to include SyntaxContext::empty(); adjusted AST ident creation sites.
React components typing expansion
rust-plugins/react-components/playground/src/types/components.d.ts
Large addition/reorganization of global component type declarations (many antd / @arco-design components and component aliases).
Worker: module format, filename ext, host_config threading, FxHashMap
rust-plugins/worker/src/lib.rs, rust-plugins/worker/playground/farm.config.ts, rust-plugins/worker/playground/src/index.tsx
Introduces ModuleFormatConfig usage, changes worker output ext to .mjs, threads host_config through worker build and compiler, replaces some HashMap with FxHashMap, removes Comlink usage in playground index and updates logs.
Tests / tooling / misc
rust-plugins/react-components/tests/mod.rs, rust-toolchain.toml, rustfmt.toml, rust-plugins/react-components/Cargo.toml
Tests switch to FxHashMap; toolchain bumped to nightly-2025-05-06; rustfmt key order adjusted; added rustc-hash dep for react-components.
Changelogs & package.json version bumps
multiple rust-plugins/*/CHANGELOG.md, rust-plugins/*/package.json, .changeset/*
Adds beta changelog entries and bumps many plugin package versions to 0.1.0-beta.0 / *-beta and adds a pre.json changeset for beta release.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Plugin as Plugin (url/wasm/worker)
  participant FS as farmfe_toolkit::fs
  Note over Plugin,FS: Structured filename generation (new TransformOutputFileNameParams)
  Plugin->>FS: transform_output_filename(TransformOutputFileNameParams{ filename_config, name, name_hash, bytes, ext, special_placeholders })
  FS-->>Plugin: output_filename (string)
Loading
sequenceDiagram
  autonumber
  actor Plugin as Plugin (react-components/strip)
  participant CM as create_swc_source_map
  participant PARSE as parse_module
  participant CODEGEN as swc_ecma_codegen
  participant SM as cm.build_source_map

  Note over Plugin: SWC parse & codegen flow with Arc content
  Plugin->>CM: create_swc_source_map(module_id, Arc<content>)
  CM-->>Plugin: (cm, src_map)
  Plugin->>PARSE: parse_module(module_id.into(), Arc<content>, ts/js options)
  PARSE-->>Plugin: { ast, .. }
  Plugin->>CODEGEN: codegen_module(ast, Config::default(), Config::default(), Some(&mut src_map))
  CODEGEN-->>Plugin: { code, map }
  Plugin->>SM: cm.build_source_map(&src_map, None, DefaultSourceMapGenConfig)
  SM-->>Plugin: sourcemap
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested reviewers

  • Maidang1
  • ErKeLost
  • wre232114

Poem

I nibble code and hop through trees, arcs of strings upon the breeze.
Bincode hides my cached delight, SWC and SVGR spark the night.
Filenames shaped from tidy plans—workers racing on mjs lands. 🥕🐇


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a63f091 and 845e77b.

📒 Files selected for processing (32)
  • .changeset/blue-crabs-fail.md (1 hunks)
  • .changeset/pre.json (1 hunks)
  • rust-plugins/auto-import/CHANGELOG.md (1 hunks)
  • rust-plugins/auto-import/package.json (1 hunks)
  • rust-plugins/compress/CHANGELOG.md (1 hunks)
  • rust-plugins/compress/package.json (1 hunks)
  • rust-plugins/dsv/CHANGELOG.md (1 hunks)
  • rust-plugins/dsv/package.json (1 hunks)
  • rust-plugins/icons/CHANGELOG.md (1 hunks)
  • rust-plugins/icons/package.json (1 hunks)
  • rust-plugins/image/CHANGELOG.md (1 hunks)
  • rust-plugins/image/package.json (1 hunks)
  • rust-plugins/mdx/CHANGELOG.md (1 hunks)
  • rust-plugins/mdx/package.json (1 hunks)
  • rust-plugins/modular-import/CHANGELOG.md (1 hunks)
  • rust-plugins/modular-import/package.json (1 hunks)
  • rust-plugins/react-components/CHANGELOG.md (1 hunks)
  • rust-plugins/react-components/package.json (1 hunks)
  • rust-plugins/strip/CHANGELOG.md (1 hunks)
  • rust-plugins/strip/package.json (1 hunks)
  • rust-plugins/svgr/CHANGELOG.md (1 hunks)
  • rust-plugins/svgr/package.json (1 hunks)
  • rust-plugins/url/CHANGELOG.md (1 hunks)
  • rust-plugins/url/package.json (1 hunks)
  • rust-plugins/virtual/CHANGELOG.md (1 hunks)
  • rust-plugins/virtual/package.json (1 hunks)
  • rust-plugins/wasm/CHANGELOG.md (1 hunks)
  • rust-plugins/wasm/package.json (1 hunks)
  • rust-plugins/worker/CHANGELOG.md (1 hunks)
  • rust-plugins/worker/package.json (1 hunks)
  • rust-plugins/yaml/CHANGELOG.md (1 hunks)
  • rust-plugins/yaml/package.json (1 hunks)
✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat-farm-v2

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@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: 10

Caution

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

⚠️ Outside diff range comments (8)
rust-plugins/dsv/src/lib.rs (1)

81-95: Remove unwraps to prevent panics on malformed CSV/TSV
A bad record currently crashes the build. Handle errors gracefully.

-    let reader = get_reader(&binding);
-
-    if reader.is_err() {
-      return Ok(None);
-    }
-
-    let mut records = vec![];
-    for result in reader.unwrap().records() {
-      let record = result.unwrap();
+    let mut reader = match get_reader(&binding) {
+      Ok(r) => r,
+      // Unsupported type or open error: opt out silently (consistent with current behavior)
+      Err(_) => return Ok(None),
+    };
+
+    let mut records = Vec::new();
+    for result in reader.records() {
+      let record = match result {
+        Ok(r) => r,
+        // Malformed content: opt out instead of panicking; consider emitting a warning if available
+        Err(_) => return Ok(None),
+      };
       let json_record: Value = record
         .iter()
         .map(|field| Value::String(field.to_string()))
         .collect();
       records.push(json_record);
     }
rust-plugins/auto-import/src/parser/parse.rs (3)

399-409: Fix lifetime bug when reading file content; avoid referencing temporaries.

You’re taking & of a temporary String from fs::read_to_string and then using it in the next statement. That reference doesn’t live long enough. Also, &file_path.into() takes a reference to a temporary String. Make both owned first, then wrap with Arc.

Apply this diff:

-  let content = if content.is_none() {
-    &fs::read_to_string(file_path)
-      .unwrap_or_else(|_| panic!("Unable to read file: {:?}", file_path))
-  } else {
-    content.unwrap()
-  };
-  let content = Arc::new(content.to_string());
-  let ParseScriptModuleResult { ast, .. } = match parse_module(
-    &file_path.into(),
-    content,
+  let content_owned: String = match content {
+    Some(c) => c.to_owned(),
+    None => fs::read_to_string(file_path)
+      .unwrap_or_else(|_| panic!("Unable to read file: {:?}", file_path)),
+  };
+  let content = Arc::new(content_owned);
+  let file_path_owned = file_path.to_string();
+  let ParseScriptModuleResult { ast, .. } = match parse_module(
+    &file_path_owned,
+    content,

439-449: Same lifetime/temporary issue in parse_esm_imports.

Mirror the fix here to avoid & of a temporary and reference to &file_path.into().

Apply this diff:

-  let content = if content.is_none() {
-    &fs::read_to_string(file_path)
-      .unwrap_or_else(|_| panic!("Unable to read file: {:?}", file_path))
-  } else {
-    content.unwrap()
-  };
-  let content = Arc::new(content.to_string());
-  let ParseScriptModuleResult { ast, .. } = match parse_module(
-    &file_path.into(),
-    content,
+  let content_owned: String = match content {
+    Some(c) => c.to_owned(),
+    None => fs::read_to_string(file_path)
+      .unwrap_or_else(|_| panic!("Unable to read file: {:?}", file_path)),
+  };
+  let content = Arc::new(content_owned);
+  let file_path_owned = file_path.to_string();
+  let ParseScriptModuleResult { ast, .. } = match parse_module(
+    &file_path_owned,
+    content,

112-116: Type-only import classification is inverted.

For ImportSpecifier::Named, type-only specifiers should populate type_named_imports; non-type should populate named_imports. Current logic is reversed.

Apply this diff:

-              if !named.is_type_only {
-                type_named_imports.insert(named.local.sym.to_string(), imported_name);
-              } else {
-                named_imports.insert(named.local.sym.to_string(), imported_name);
-              }
+              if named.is_type_only {
+                type_named_imports.insert(named.local.sym.to_string(), imported_name);
+              } else {
+                named_imports.insert(named.local.sym.to_string(), imported_name);
+              }
rust-plugins/auto-import/src/parser/scan_exports.rs (1)

27-52: Escape import specifiers to generate valid JS on all platforms

Current stringify emits raw paths inside single quotes; Windows backslashes and quotes can break the string. Prior learning recommends using {:?} to ensure proper escaping.

Using the retrieved learnings noted earlier, update the format strings:

-      ExportType::DefaultDecl => format!("import {} from '{}';\n", self.name, self.from),
+      ExportType::DefaultDecl => format!("import {} from {:?};\n", self.name, self.from),
@@
-        format!("import {{ {} }} from '{}';\n", self.name, self.from)
+        format!("import {{ {} }} from {:?};\n", self.name, self.from)
@@
-            format!(
-              "import {{ {} as {} }} from '{}';\n",
-              self.name, as_name, self.from
-            )
+            format!(
+              "import {{ {} as {} }} from {:?};\n",
+              self.name, as_name, self.from
+            )
@@
-          format!("import {{ {} }} from '{}';\n", self.name, self.from)
+          format!("import {{ {} }} from {:?};\n", self.name, self.from)
@@
-      ExportType::Type => format!("import {{ type {} }} from '{}';\n", self.name, self.from),
+      ExportType::Type => format!("import {{ type {} }} from {:?};\n", self.name, self.from),
rust-plugins/wasm/src/lib.rs (1)

78-83: Fix filename split, bytes type, and temporary reference in params

  • split_once('.') breaks on names with multiple dots; use Path::file_stem/extension.
  • bytes: &param.module_id.as_bytes() yields &&[u8]; pass param.module_id.as_bytes().
  • special_placeholders takes a reference to a temporary Default; inline the params in the call or bind a local to extend lifetime.

Apply this diff:

-      let file_name_ext = Path::new(wasm_file_path)
-        .file_name()
-        .map(|x| x.to_string_lossy().to_string())
-        .unwrap();
-      let (file_name, ext) = file_name_ext.split_once('.').unwrap();
+      let path = Path::new(wasm_file_path);
+      let file_name = path
+        .file_stem()
+        .and_then(|x| x.to_str())
+        .expect("wasm file_stem should be valid UTF-8");
+      let ext = path
+        .extension()
+        .and_then(|x| x.to_str())
+        .unwrap_or("wasm");
@@
-      let transform_output_file_name_params = TransformOutputFileNameParams {
-        filename_config: assets_filename_config,
-        name: file_name,
-        name_hash: "",
-        bytes: &param.module_id.as_bytes(),
-        ext,
-        special_placeholders: &Default::default(),
-      };
-      let output_file_name = transform_output_filename(transform_output_file_name_params);
+      let output_file_name = transform_output_filename(TransformOutputFileNameParams {
+        filename_config: assets_filename_config,
+        name: file_name,
+        name_hash: "",
+        bytes: param.module_id.as_bytes(),
+        ext,
+        special_placeholders: &Default::default(),
+      });

Also applies to: 84-93

rust-plugins/worker/src/lib.rs (2)

301-310: Validate compiler config parsing

The compiler config parsing silently ignores errors with .ok(), which could lead to None being used later when the code expects Some.

Instead of silently ignoring parsing errors, consider logging them or handling them appropriately:

-        compiler_config: serde_json::from_value(compiler_config).ok(),
+        compiler_config: match serde_json::from_value(compiler_config) {
+          Ok(config) => Some(config),
+          Err(e) => {
+            eprintln!("Warning: Failed to parse compiler config: {}", e);
+            None
+          }
+        },

199-200: The cache lookup at line 199 uses resolved_path, but earlier in the same function only file_name is ever used as the key when inserting into worker_cache. This mismatch means unwrap() here can indeed panic because that key may never have been inserted. Replace the unwrap with an explicit error or use the same key (file_name) consistently:

-      let content_bytes = worker_cache.get(resolved_path).unwrap();
+      // Use the same key as in insertion, or handle missing entry explicitly
+      let content_bytes = worker_cache
+        .get(&file_name)
+        .unwrap_or_else(|| panic!("Expected worker_cache to contain `{}`", file_name));
🧹 Nitpick comments (36)
rust-plugins/react-components/tests/mod.rs (1)

76-79: Use Default::default for consistency and easier future type changes.

Keeps style uniform and decouples construction from the concrete map/vector types.

-    meta: FxHashMap::default(),
+    meta: Default::default(),
     source_map_chain: vec![],
-    query: vec![],
+    query: Default::default(),
rust-plugins/react-components/playground/src/types/components.d.ts (3)

19-19: Normalize naming for lowercase antd utilities.

For consistency with PascalCase globals, consider renaming:

  • Antversion → AntVersion
  • Antnotification → AntNotification
  • Antmessage → AntMessage
  • Anttheme → AntTheme

Apply locally (adjust your generator):

-const Antversion: typeof import('antd')['version']
+const AntVersion: typeof import('antd')['version']
-const Antnotification: typeof import('antd')['notification']
+const AntNotification: typeof import('antd')['notification']
-const Antmessage: typeof import('antd')['message']
+const AntMessage: typeof import('antd')['message']
-const Anttheme: typeof import('antd')['theme']
+const AntTheme: typeof import('antd')['theme']

Also applies to: 81-81, 98-98, 145-145


127-127: Verify Arco Trigger export path.

Check that '@arco-design/web-react' actually re-exports Trigger at the root. If not, point the type to its module entry (commonly '/es/Trigger' or '/Trigger') or drop it.

Possible fallback:

-const ArcoTrigger: typeof import('@arco-design/web-react')['Trigger']
+const ArcoTrigger: typeof import('@arco-design/web-react/es/Trigger')['default']

(Adjust path per the installed version.)


12-144: Reduce global surface area (optional).

To cut churn and collisions, consider exposing just two globals and deprecate per-component names:

declare global {
  const Ant: typeof import('antd');
  const Arco: typeof import('@arco-design/web-react');
}
export {};

This keeps usage ergonomic (Ant.Button, Arco.Modal) and future-proof as libraries add/remove exports.

rust-plugins/worker/playground/package.json (1)

21-27: Align CLI/dev tool versions (optional).

CLI is ^1.0.4 here but ^1.0.2 in other playbooks; consider standardizing to reduce drift.

rust-plugins/auto-import/playground-vue/package.json (1)

16-21: Optional: unify CLI version across playgrounds.

Consider aligning @farmfe/cli with other examples for consistency.

rustfmt.toml (1)

2-2: No functional change; OK to keep.

Key reordering is harmless. If unintentional churn, consider reverting to minimize diffs.

rust-plugins/wasm/playground/package.json (1)

21-27: Optional: normalize React deps across examples.

This playground uses ^18.3.x while others pin "18". Consider aligning policy.

rust-plugins/react-components/Cargo.toml (1)

21-21: Document/centralize rustc-hash usage.

If multiple crates use rustc-hash, consider moving it to [workspace.dependencies] to keep versions in sync; add a short comment on why FxHasher is chosen.

rust-plugins/worker/Cargo.toml (1)

19-20: rkyv 0.8 bump: confirm feature flags; FxHash caution if keys are persisted

  • If you rely on zero-copy validation or runtime checks, enable rkyv’s validation/bytecheck features explicitly.
  • FxHash (rustc-hash) is great for perf, but its hash is not stable across versions/platforms—avoid using it for cache keys persisted to disk or across processes.
-rkyv = "0.8.10"
+// enable if you need archived type validation; otherwise keep as-is
+rkyv = { version = "0.8.10", features = ["validation", "bytecheck"] }
rust-plugins/dsv/src/lib.rs (2)

41-55: Handle extensions case-insensitively and set has_headers explicitly
This avoids surprises on uppercased extensions and makes header handling deterministic.

 fn get_reader(param: &Param) -> Result<Reader<&[u8]>, Box<dyn Error>> {
-  let extname = Path::new(&param.module_id)
+  let extname = Path::new(&param.module_id)
     .extension()
     .ok_or("No file extension found")?
     .to_str()
     .ok_or("File extension cannot be converted to string")?;
 
-  let reader = match extname {
-    "csv" => ReaderBuilder::new().from_reader(param.content.as_bytes()),
-    "tsv" => ReaderBuilder::new()
-      .delimiter(b'\t')
-      .from_reader(param.content.as_bytes()),
+  let ext = extname.to_ascii_lowercase();
+  let reader = match ext.as_str() {
+    "csv" => ReaderBuilder::new()
+      .has_headers(false)
+      .from_reader(param.content.as_bytes()),
+    "tsv" => ReaderBuilder::new()
+      .has_headers(false)
+      .delimiter(b'\t')
+      .from_reader(param.content.as_bytes()),
     _ => return Err("Unsupported file type".into()),
   };
 
   Ok(reader)
 }

31-34: Avoid startup panic on invalid options
Parsing options with unwrap() will crash initialization. Prefer a fall-back or a clear error.

 impl FarmPluginDsv {
   fn new(_config: &Config, options: String) -> Self {
-    let options: Options = serde_json::from_str(&options).unwrap();
+    let options: Options = serde_json::from_str(&options)
+      .unwrap_or(Options { include: None, exclude: None });
     Self { options }
   }
 }
rust-plugins/image/src/lib.rs (2)

55-57: Surface I/O errors instead of emitting an empty data URI.

Encoding an empty vec yields data:...;base64, and hides real file-read failures. Prefer propagating the error or returning Ok(None) with a diagnostic.

Example (sketch):

let bytes = read_file_raw(&param.resolved_path)
  .map_err(|e| farmfe_core::error::Error::new(e.to_string()))?;
let file_base64 = general_purpose::STANDARD.encode(bytes);

46-47: Minor: simplify with unwrap_or_default().

let include = options.include.unwrap_or_default();
let exclude = options.exclude.unwrap_or_default();
rust-plugins/worker/playground/farm.config.ts (1)

22-24: Make runtime.path env-configurable to support subpath deployments.

Hard-coding "/" breaks when served under a base path.

-        runtime: {
-          path: "/"
-        }
+        runtime: {
+          path: process.env.BASE_URL ?? "/"
+        }

Please confirm this matches the 2.x config shape for compilation.runtime.path.

Cargo.toml (1)

7-12: Consider loosening to caret/major ranges to pick up patch releases automatically.

Keeps reproducibility while allowing security/bugfix patches.

-farmfe_core = { version = "2.0.0" }
-farmfe_utils = { version = "2.0.0" }
-farmfe_toolkit_plugin_types = { version = "2.0.0" }
-farmfe_macro_plugin = { version = "2.0.0" }
-farmfe_toolkit = "2.0.0"
-farmfe_compiler = { version = "2.0.0" }
+farmfe_core = { version = "2" }
+farmfe_utils = { version = "2" }
+farmfe_toolkit_plugin_types = { version = "2" }
+farmfe_macro_plugin = { version = "2" }
+farmfe_toolkit = "2"
+farmfe_compiler = { version = "2" }
rust-plugins/svgr/src/react_compiler.rs (1)

12-21: Avoid unwrap(); return a Result to bubble up transform errors.

Example:

pub fn react_compiler(param: CompilerParams) -> anyhow::Result<String> {
  let CompilerParams { svg, .. } = param;
  let code = _react_compiler(
    svg,
    Config { jsx_runtime: JSXRuntime::Classic, ..Default::default() },
    Default::default(),
  )?;
  Ok(code)
}
rust-plugins/modular-import/Cargo.toml (1)

15-15: Optional: lift regex to workspace.dependencies to avoid duplicates

Multiple crates may use regex; centralizing in [workspace.dependencies] keeps a single semver across the repo.

rust-plugins/url/Cargo.toml (1)

16-17: LGTM; consider moving serde to workspace for uniform version/feature flags

Using serde with derive is fine here; for consistency and to prevent duplicates, consider [workspace.dependencies] serde = { version = "1.x", features=["derive"] }.

rust-plugins/icons/src/compiler/preact.rs (2)

15-15: Avoid unwrap: surface transform errors with context

Prevent panics in plugin code paths by adding context or propagating the error.

-  )
-  .unwrap();
+  )
+  .unwrap_or_else(|e| panic!("svgr transform (preact) failed: {e}"));

If you can change the signature, prefer returning Result<String, E> and bubble up.


1-1: Nit: “complier” → “compiler” (typo in alias and function name)

Renaming improves readability and searchability.

-pub use svgr_rs::{transform as react_complier, Config, JSXRuntime};
+pub use svgr_rs::{transform as react_compiler, Config, JSXRuntime};

-pub fn preact_complier(param: CompilerParams) -> String {
+pub fn preact_compiler(param: CompilerParams) -> String {

-  let code = react_complier(
+  let code = react_compiler(

Also applies to: 5-5, 7-7

rust-plugins/auto-import/src/parser/parse.rs (1)

258-276: Simplify TsModule id extraction (readability).

This chain clones and unwraps multiple times. A simple if let avoids redundant clones and unwraps.

Suggested refactor (outside changed lines):

let name = if let Some(s) = module_decl.id.clone().str() {
  s.value.to_string()
} else if let Some(id) = module_decl.id.clone().ident() {
  id.sym.to_string()
} else {
  "Anonymous".to_string()
};
rust-plugins/icons/src/cache/mod.rs (2)

53-58: Avoid unwrap() on encode; propagate an error instead.

If encoding fails, fail the request rather than panic.

Apply this diff:

-          let serialized_data = bincode::encode_to_vec(&cache_value, config).unwrap();
-          self
-            .cache
-            .connection()
-            .insert(url.to_string(), serialized_data)
-            .unwrap();
+          let serialized_data = bincode::encode_to_vec(&cache_value, config)
+            .map_err(|e| {
+              loading.fail(format!("{} icon cache encode err: {:?}", url, e));
+              e
+            })?;
+          let _ = self.cache.connection().insert(url.to_string(), serialized_data);

41-46: Reuse an HTTP client for connection pooling.

reqwest::get creates a new client each time. Consider injecting a reqwest::Client into HttpClient to reuse connections.

If desired, I can draft the change.

rust-plugins/icons/src/compiler/react.rs (1)

1-5: Nit: fix “complier” typo in local alias for clarity

Rename the alias to reduce confusion; safe, local-only change.

-pub use svgr_rs::{transform as _react_complier, Config, JSXRuntime};
+pub use svgr_rs::{transform as _react_compiler, Config, JSXRuntime};
@@
-  let code = _react_complier(
+  let code = _react_compiler(
rust-plugins/auto-import/src/parser/scan_dirs_exports.rs (2)

19-19: Harden path/extension handling (avoid panics; handle case-insensitive extensions)

to_str().unwrap() can panic on non-UTF8 paths, and ext matching is case-sensitive. Prefer lossy conversion and lowercase ext.

Apply this diff:

-    let exports_names = scan_exports(&normalize_path(file_path.to_str().unwrap()), None);
+    let path_str = file_path.to_string_lossy();
+    let exports_names = scan_exports(&normalize_path(&path_str), None);
@@
-        let normalized_path = normalize_path(e.path().to_str().unwrap());
-        if filter.execute(&normalized_path)
-          && e.path().extension().is_some()
-          && file_exts.contains(&e.path().extension().unwrap().to_str().unwrap())
+        let normalized_path = normalize_path(&e.path().to_string_lossy());
+        let ext_lc = e
+          .path()
+          .extension()
+          .and_then(|s| s.to_str())
+          .map(|s| s.to_ascii_lowercase());
+        if filter.execute(&normalized_path)
+          && ext_lc
+            .as_deref()
+            .is_some_and(|ext| file_exts.iter().any(|e| e.eq_ignore_ascii_case(ext)))

Also applies to: 41-45


30-30: Prefer slices over &Vec in params

Use &[ConfigRegex] to avoid forcing callers to allocate a Vec.

-pub fn scan_dirs_exports(root_path: &str, dirs: &Vec<ConfigRegex>) -> Vec<Import> {
+pub fn scan_dirs_exports(root_path: &str, dirs: &[ConfigRegex]) -> Vec<Import> {
rust-plugins/react-components/src/find_local_components.rs (2)

330-335: Avoid referencing a temporary PathBuf; pass a Path directly

&components_path.clone().into() borrows a temporary. Use Path::new(&components_path) (or prebind a PathBuf) for clarity and to avoid accidental lifetime pitfalls.

-  let ParseScriptModuleResult { ast,..} = match parse_module(
-    &components_path.clone().into(),
-    file_content,
+  let ParseScriptModuleResult { ast, .. } = match parse_module(
+    std::path::Path::new(&components_path),
+    file_content,

382-385: Normalize path using lossy conversion to avoid panics

Minor robustness improvement when normalizing OS paths.

-        let normalized_path = normalize_path(e.path().to_str().unwrap());
+        let normalized_path = normalize_path(&e.path().to_string_lossy());
rust-plugins/wasm/src/lib.rs (1)

101-121: String formatting is fine; consider trimming shared indent

Not critical, but the emitted JS contains leading spaces. Using indoc! or a raw string without indentation could reduce bytes.

rust-plugins/strip/src/lib.rs (3)

113-114: Potential Arc usage inefficiency

The content is being cloned and wrapped in Arc twice - once for create_swc_source_map and again for parse_module. Consider reusing the Arc-wrapped content.

-    let (cm, _) =
-      create_swc_source_map(&param.resolved_path.into(), Arc::new(param.content.clone()));
+    let content = Arc::new(param.content.clone());
+    let (cm, _) = create_swc_source_map(&param.resolved_path.into(), content.clone());

Then update line 119:

-      Arc::new(param.content.clone()),
+      content,

82-84: Simplify boolean comparison logic

The source_map check can be simplified by using unwrap_or(false) directly.

-    let source_map = match options.source_map {
-      Some(s) => s != false,
-      None => false,
-    };
+    let source_map = options.source_map.unwrap_or(false);

86-89: Simplify debugger option handling

Similar to the source_map option, this can be simplified.

-    let remove_debugger_statements = match options.debugger {
-      Some(s) => s != false,
-      None => false,
-    };
+    let remove_debugger_statements = options.debugger.unwrap_or(false);
rust-plugins/react-components/src/lib.rs (1)

164-170: Redundant Arc wrapping of content

Similar to the strip plugin, the content is being cloned and wrapped in Arc twice. Consider reusing the Arc-wrapped content.

-    let content = Arc::new(param.content.clone());
-    let (cm, _) = create_swc_source_map(&param.module_id.clone().into(), content);
-    let ParseScriptModuleResult {
-      mut ast, comments, ..
-    } = match parse_module(
-      &param.module_id.clone().into(),
-      Arc::new(param.content.clone()),
+    let content = Arc::new(param.content.clone());
+    let (cm, _) = create_swc_source_map(&param.module_id.clone().into(), content.clone());
+    let ParseScriptModuleResult {
+      mut ast, comments, ..
+    } = match parse_module(
+      &param.module_id.clone().into(),
+      content,
rust-plugins/worker/src/lib.rs (2)

113-120: Fix indentation inconsistency

The TransformOutputFileNameParams initialization has inconsistent indentation.

-      let transform_output_file_name_params = TransformOutputFileNameParams {
-        filename_config: assets_filename_config,
-        name: file_name,
-        name_hash: "",
-        bytes: &module_id.as_bytes(),
-        ext,
-        special_placeholders: &Default::default(),
-      };
+  let transform_output_file_name_params = TransformOutputFileNameParams {
+    filename_config: assets_filename_config,
+    name: file_name,
+    name_hash: "",
+    bytes: &module_id.as_bytes(),
+    ext,
+    special_placeholders: &Default::default(),
+  };

55-57: Consider using more descriptive variable name

The variable name _worker_url is prefixed with underscore but it's actually being used (file_name is extracted from get_worker_url). Consider renaming for clarity.

-  let (_worker_url, full_file_name) = get_worker_url(resolved_path, module_id, compiler_config);
+  let (worker_url, full_file_name) = get_worker_url(resolved_path, module_id, compiler_config);
+  let _ = worker_url; // Explicitly mark as unused if not needed
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c6f8452 and 8662f4d.

⛔ Files ignored due to path filters (5)
  • Cargo.lock is excluded by !**/*.lock
  • rust-plugins/auto-import/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • rust-plugins/react-components/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • rust-plugins/wasm/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • rust-plugins/worker/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (37)
  • Cargo.toml (1 hunks)
  • rust-plugins/auto-import/playground-react/package.json (1 hunks)
  • rust-plugins/auto-import/playground-vue/package.json (1 hunks)
  • rust-plugins/auto-import/src/lib.rs (1 hunks)
  • rust-plugins/auto-import/src/parser/parse.rs (4 hunks)
  • rust-plugins/auto-import/src/parser/scan_dirs_exports.rs (1 hunks)
  • rust-plugins/auto-import/src/parser/scan_exports.rs (1 hunks)
  • rust-plugins/compress/Cargo.toml (1 hunks)
  • rust-plugins/dsv/src/lib.rs (1 hunks)
  • rust-plugins/icons/Cargo.toml (1 hunks)
  • rust-plugins/icons/src/cache/mod.rs (3 hunks)
  • rust-plugins/icons/src/compiler/preact.rs (1 hunks)
  • rust-plugins/icons/src/compiler/react.rs (1 hunks)
  • rust-plugins/icons/src/lib.rs (1 hunks)
  • rust-plugins/image/src/lib.rs (1 hunks)
  • rust-plugins/modular-import/Cargo.toml (1 hunks)
  • rust-plugins/react-components/Cargo.toml (1 hunks)
  • rust-plugins/react-components/playground/package.json (2 hunks)
  • rust-plugins/react-components/playground/src/types/components.d.ts (1 hunks)
  • rust-plugins/react-components/src/find_local_components.rs (2 hunks)
  • rust-plugins/react-components/src/insert_import.rs (3 hunks)
  • rust-plugins/react-components/src/lib.rs (5 hunks)
  • rust-plugins/react-components/tests/mod.rs (2 hunks)
  • rust-plugins/strip/src/lib.rs (6 hunks)
  • rust-plugins/svgr/Cargo.toml (1 hunks)
  • rust-plugins/svgr/src/react_compiler.rs (1 hunks)
  • rust-plugins/url/Cargo.toml (1 hunks)
  • rust-plugins/url/src/lib.rs (3 hunks)
  • rust-plugins/wasm/Cargo.toml (1 hunks)
  • rust-plugins/wasm/playground/package.json (1 hunks)
  • rust-plugins/wasm/src/lib.rs (2 hunks)
  • rust-plugins/worker/Cargo.toml (1 hunks)
  • rust-plugins/worker/playground/farm.config.ts (1 hunks)
  • rust-plugins/worker/playground/package.json (1 hunks)
  • rust-plugins/worker/src/lib.rs (5 hunks)
  • rust-toolchain.toml (1 hunks)
  • rustfmt.toml (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-02-24T06:59:13.009Z
Learnt from: fu050409
PR: farm-fe/plugins#115
File: rust-plugins/wasm/src/utils.rs:71-80
Timestamp: 2025-02-24T06:59:13.009Z
Learning: When generating JavaScript import statements from file paths in Rust, use `{:?}` format specifier instead of `{}` to ensure proper escaping of special characters in paths (e.g., `"".txt` → `\"\"`).

Applied to files:

  • rust-plugins/auto-import/src/parser/scan_exports.rs
🧬 Code graph analysis (5)
rust-plugins/auto-import/src/parser/scan_dirs_exports.rs (1)
rust-plugins/virtual/src/utils.rs (1)
  • normalize_path (57-80)
rust-plugins/auto-import/src/parser/scan_exports.rs (1)
rust-plugins/virtual/src/utils.rs (1)
  • normalize_path (57-80)
rust-plugins/wasm/src/lib.rs (1)
rust-plugins/wasm/src/utils.rs (1)
  • generate_glue_code (64-125)
rust-plugins/worker/src/lib.rs (1)
rust-plugins/worker/tests/mod.rs (1)
  • Regex (90-90)
rust-plugins/react-components/src/find_local_components.rs (1)
rust-plugins/virtual/src/utils.rs (1)
  • normalize_path (57-80)
🔇 Additional comments (33)
rust-plugins/react-components/playground/src/types/components.d.ts (2)

12-18: LGTM on ambient typings pattern.

Using declare global with typeof import(...) keeps globals aligned with library types. No issues spotted in this block.


12-12: Deps and tsconfig include verified: antd and @arco-design/web-react are listed in package.json, and tsconfig.json’s "include": ["src"] covers src/types/components.d.ts.

rust-plugins/auto-import/playground-vue/package.json (1)

17-17: LGTM on Farm v2 bump.

Version string is correct ("beta"); no issues spotted.

rust-plugins/dsv/src/lib.rs (2)

3-3: PathFilter import migration looks good
No functional change; aligns with toolkit’s new module path.


98-103: Verify module_type for Farm 2.x
Confirm that ModuleType::Custom("json") is still the intended type for “export default ” modules in v2. If the loader expects JS, switch to ModuleType::Js.

rust-toolchain.toml (1)

2-2: Toolchain bump acknowledged; ensure CI/dev envs are pinned
Looks good. Please confirm CI installs nightly-2025-05-06 to avoid drift.

rust-plugins/auto-import/playground-react/package.json (1)

20-21: Align prerelease version spec across playgrounds and verify CLI compatibility

-    "@farmfe/core": "^2.0.0-beta.0",
-    "@farmfe/plugin-react": "^2.0.0-beta.0",
+    "@farmfe/core": "2.0.0-beta.0",
+    "@farmfe/plugin-react": "2.0.0-beta.0",

Manually confirm that @farmfe/cli@^1.x is compatible with Core 2.x.

rust-plugins/react-components/playground/package.json (1)

14-14: Unify Farm plugin version channels
js-plugin-less is pinned to nightly (2.0.0-nightly-20250827162746) but there’s no 2.0.0-beta publish and the stable “latest” is 1.13.0. Align all Farm plugins in package.json to a single channel—either nightly (^2.0.0-nightly-…) across the board or stable (^1.13.0)—to prevent drift.

rust-plugins/image/src/lib.rs (1)

11-12: Import path relocation to toolkit 2.x looks correct.

Reads clean and aligns with the new module layout.

rust-plugins/svgr/Cargo.toml (1)

17-19: Loosen Cargo.toml pins for svgr-rs and xmltree

--- rust-plugins/svgr/Cargo.toml
-svgr-rs = "0.2.0"
+svgr-rs = "0.2"
-xmltree = "0.11.0"
+xmltree = "0.11"

Verify JSXRuntime::Classic and xmltree::Element APIs remain unchanged in patch releases.

rust-plugins/svgr/src/react_compiler.rs (2)

15-15: JSXRuntime enum update is correct for svgr-rs 0.2.

Matches the non-optional API.


15-15: Consider exposing runtime selection.

If consumers use React 17+ with automatic runtime, allow opting into JSXRuntime::Automatic.

rust-plugins/icons/Cargo.toml (4)

17-17: All JSXRuntime callers updated to non-Option No Option<JSXRuntime> remains in preact, react, or any tests/fixtures.


14-14: No duplicate farmfe_utils versions found All workspace crates use workspace = true, inheriting version 2.0.0 from the root Cargo.toml.


23-23: No xmltree 0.11 API changes impact svg_builder.rs
Scan of rust-plugins/icons/src/loader/svg_builder.rs shows only use xmltree::Element, the Element type, and the Element::parse method—both of which remain unchanged in xmltree 0.11.0 (eminence.github.io)


27-27: No action required: disk_store feature correct and no MSRV change
Upstream cached v0.56.0 defines the disk_store feature exactly as used and does not declare a rust-version, so bumping to 0.56.0 introduces no MSRV impact.

rust-plugins/wasm/Cargo.toml (2)

10-13: Workspace dep switch LGTM

Moving core farm crates to workspace = true is consistent and reduces version drift.


10-15: Remove validation/bytecheck suggestion: no Archive/Deserialize derives detected

Search for #[derive(Archive)] and bytecheck in rust-plugins/wasm returned no matches—enabling rkyv validation features is unnecessary.

rust-plugins/modular-import/Cargo.toml (1)

10-12: Workspace alignment LGTM

Good consolidation to workspace-managed versions.

rust-plugins/icons/src/compiler/preact.rs (1)

10-11: JSX runtime update LGTM; mirrors svgr-rs 0.2 non-Option field

Change looks correct and consistent with the new API.

rust-plugins/react-components/src/insert_import.rs (2)

1-1: SWC API migration to Ident::new(..., SyntaxContext::empty()) looks correct.

Calls are updated consistently for default and named specifiers and re-exports.

Also applies to: 133-145


62-69: Mutex lock scope is short and cloned before release — good.

This avoids holding the lock while mutating used_components.

rust-plugins/auto-import/src/lib.rs (1)

21-21: Import path update to plugin_utils is correct for v2

Looks consistent with the toolkit re-org. Please ensure all sibling modules use the same path to avoid mixed imports.

rust-plugins/auto-import/src/parser/scan_exports.rs (1)

6-7: Fixed normalize_path import path

Correcting to plugin_utils aligns with the new layout. No further changes needed here.

rust-plugins/icons/src/compiler/react.rs (1)

10-10: JSX runtime no longer optional: confirm svgr_rs API match

Setting jsx_runtime directly implies svgr_rs Config changed. Ensure the workspace pins svgr_rs to the version where jsx_runtime is non-Option, or this will fail to compile.

rust-plugins/icons/src/lib.rs (1)

47-47: Avoid unwrapping cache_dir to prevent panics when persistent cache is disabled
Replace the unwrap() with a safe fallback, for example:

- let cache_dir = config.persistent_cache.as_obj(&config.root).cache_dir.unwrap();
+ let cache_dir = config
+   .persistent_cache
+   .as_obj(&config.root)
+   .cache_dir
+   .unwrap_or_else(|| {
+     let fallback = std::env::temp_dir().join("farmfe-icons-cache");
+     let _ = std::fs::create_dir_all(&fallback);
+     fallback
+   });

If you’re confident v2 always provides a directory, use expect("cache_dir must be set") instead.
Verify that PersistentCacheConfig::Bool(false) leads to None for cache_dir in as_obj, and audit the repo for other persistent_cache…unwrap() calls.

rust-plugins/auto-import/src/parser/scan_dirs_exports.rs (1)

3-3: Import path migration looks correct

Using plugin_utils::{normalize_path, PathFilter} matches the v2 layout.

rust-plugins/react-components/src/find_local_components.rs (2)

8-9: Import reorg aligns with toolkit v2

plugin_utils::{normalize_path, PathFilter} and script::{parse_module, ParseScriptModuleResult} look good.


11-11: Arc import LGTM

Arc-wrapping file content matches the new parse_module API.

rust-plugins/wasm/src/lib.rs (2)

12-13: Required traits imported

Bringing Cacheable into scope is necessary for #[cache_item]. Good.


18-18: API migration acknowledged

Switch to TransformOutputFileNameParams matches the new toolkit fs API.

rust-plugins/url/src/lib.rs (2)

24-26: Imports updated correctly

fs::{TransformOutputFileNameParams, read_file_raw, transform_output_filename} and plugin_utils::PathFilter are correct for v2.


167-168: Signature update acknowledged

finalize_resources now uses PluginFinalizeResourcesHookParam; change looks consistent.

Comment on lines +7 to +12
farmfe_core = { version = "2.0.0" }
farmfe_utils = { version = "2.0.0" }
farmfe_toolkit_plugin_types = { version = "2.0.0" }
farmfe_macro_plugin = { version = "2.0.0" }
farmfe_toolkit = "2.0.0"
farmfe_compiler = { version = "2.0.0" }
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify no stale pre-2.x imports/usages remain.

Run:


🏁 Script executed:

#!/bin/bash
# old PathFilter location and other likely renames
rg -n 'farmfe_toolkit::common::PathFilter|normalize_path\(|TransformOutputFileNameParams|PluginTransformHookParam\s*\{|PluginLoadHookParam\s*\{' -S -g '!**/target/**'

Length of output: 2103


Update or remove all stale pre-2.x FarmFE API usages
Stale imports and calls remain across the rust-plugins crates (wasm, virtual, url, worker, react-components, auto-import). You must replace or remove references to the old APIs—e.g.

  • farmfe_toolkit::fs::{transform_output_filename, TransformOutputFileNameParams}
  • normalize_path(...)
  • PluginTransformHookParam { … } / PluginLoadHookParam { … }
🤖 Prompt for AI Agents
Cargo.toml lines 7-12: the project is pinned to FarmFE 2.0.0 but the
rust-plugins crates still reference pre-2.x FarmFE APIs; update or remove those
stale imports and usages across the rust-plugins crates (wasm, virtual, url,
worker, react-components, auto-import). Search for and replace removed APIs such
as farmfe_toolkit::fs::{transform_output_filename,
TransformOutputFileNameParams}, normalize_path(...), and old
PluginTransformHookParam/PluginLoadHookParam structures with their 2.x
equivalents or new utility functions/types provided by
farmfe_toolkit/farmfe_utils, refactor hook signatures to match the new
trait/type names, and remove any no-longer-needed helper wrappers; ensure
compilation by running cargo check and update Cargo.toml dependency entries only
if you need to change feature flags or versions for the new APIs.

Comment on lines +485 to 489
let content = Arc::new(content.to_string());
let ParseScriptModuleResult { ast, .. } = match parse_module(
&file_path.into(),
content,
Syntax::Typescript(TsSyntax {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Same lifetime/temporary issue in parse_esm_exports.

Repeat the ownership fix here as well.

Apply this diff:

-  let content = Arc::new(content.to_string());
-  let ParseScriptModuleResult { ast, .. } = match parse_module(
-    &file_path.into(),
-    content,
+  let content_owned: String = match content {
+    Some(c) => c.to_owned(),
+    None => fs::read_to_string(file_path)
+      .unwrap_or_else(|_| panic!("Unable to read file: {:?}", file_path)),
+  };
+  let content = Arc::new(content_owned);
+  let file_path_owned = file_path.to_string();
+  let ParseScriptModuleResult { ast, .. } = match parse_module(
+    &file_path_owned,
+    content,

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In rust-plugins/auto-import/src/parser/parse.rs around lines 485-489,
parse_esm_exports suffers the same temporary/lifetime ownership issue as
earlier: create an Arc<String> for the file content (e.g. let content =
Arc::new(content.to_string());) and pass that Arc (or content.clone()) into
parse_module instead of the temporary string slice so the AST retains a valid
owned reference; update the call site to use the Arc value and adjust any
parameter types if necessary to accept Arc<String>.

Comment on lines +10 to +12
farmfe_core = { workspace = true }
farmfe_toolkit_plugin_types = { workspace = true }
farmfe_macro_plugin = { workspace = true }
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Workspace deps switch: verify workspace pins exist and match farm v2

Looks good, but compilation will fail if these crates aren’t declared in [workspace.dependencies] at the root or versions drift from 2.x. Please verify.

Run:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "Workspace root and dependency pins:"
rg -nP '^\[workspace\]' -n Cargo.toml || true
rg -nP '^\[workspace\.dependencies\]' -n Cargo.toml -C3 || true
echo
echo "Looking for farmfe workspace deps:"
rg -nP '^\s*(farmfe_core|farmfe_toolkit_plugin_types|farmfe_macro_plugin)\s*=' **/Cargo.toml -g '!**/target/**' -C1

Length of output: 674


Add missing farmfe_macro_plugin to root [workspace.dependencies] and align versions
The root Cargo.toml’s [workspace.dependencies] currently pins farmfe_core, farmfe_utils, and farmfe_toolkit_plugin_types at version 2.0.0 but omits farmfe_macro_plugin. Add:

[workspace.dependencies]

farmfe_macro_plugin = { version = "2.0.0" }

and ensure all farmfe_* deps remain on 2.x to prevent build breaks.

🤖 Prompt for AI Agents
In rust-plugins/compress/Cargo.toml around lines 10 to 12, the workspace
dependencies list includes farmfe_core and farmfe_toolkit_plugin_types but omits
farmfe_macro_plugin and the versions must be aligned to 2.x; add
farmfe_macro_plugin to the [workspace.dependencies] section with version "2.0.0"
(and verify all other farmfe_* entries are set to version "2.0.0") so all
farmfe_* dependencies remain on the 2.x line to prevent build breaks.

Comment on lines +27 to +28
cached = { version = "0.56.0", features = ["disk_store"] }
bincode = "2.0.1"
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Disk cache compatibility: bincode v2 breaks v1 cache format—bump cache version or handle decode fallback

Upgrading bincode 1.x → 2.x will make previously persisted cache entries unreadable. To avoid hard failures and stale cache reuse, version your on-disk cache keys or add a graceful v1→v2 fallback.

If you already did this elsewhere, ignore. Otherwise, I can generate a small helper (CacheHeader { version: 2, ... }) and wire it into the read/write path—want me to send a patch?


🏁 Script executed:

#!/bin/bash
# Verify whether cache versioning exists or bincode is used directly.
rg -nS 'bincode::' rust-plugins/icons
rg -nS 'version' rust-plugins/icons | rg -nS 'cache|icon'

Length of output: 4709


Version on-disk cache entries for bincode v2 compatibility
bincode v2 (bincode = "2.0.1" in Cargo.toml) changes the wire format and will break reads of any files written with v1. In rust-plugins/icons/src/cache/mod.rs, both

let cached_value: (CacheValue, usize) = bincode::decode_from_slice(&entry, config).unwrap();  
let serialized_data = bincode::encode_to_vec(&cache_value, config).unwrap();

assume a headerless payload. Add a small version header (e.g. a u8 or u16 before the bincode blob), bump it to 2 for new entries, and implement fallback logic to decode v1 when the header indicates version 1.

🤖 Prompt for AI Agents
In rust-plugins/icons/Cargo.toml around lines 27-28 and corresponding
rust-plugins/icons/src/cache/mod.rs, the on-disk bincode wire format changed in
bincode v2 so existing headerless v1 payloads will fail to decode; modify the
cache read/write to prepend a small version header (use a u8, write 2 for new
entries) before the bincode blob when serializing, and when deserializing first
read the header byte: if it equals 2 decode the following bytes with the current
bincode v2 config, if it indicates legacy (missing header or value 1) fall back
to the v1 decode path (attempt decode without header or use a v1-compatible
config) so existing files remain readable; ensure writers always write the
version byte 2 and update error handling/logging for both branches.

Comment on lines +27 to 35
let config = config::standard();
if let Ok(Some(entry)) = self.cache.connection().get(url) {
let cached_value: CacheValue = bincode::deserialize(&entry).unwrap();
if cached_value.expiration > SystemTime::now() {
let cached_value:(CacheValue, usize) = bincode::decode_from_slice(&entry, config).unwrap();
if cached_value.0.expiration > SystemTime::now() {
// Return cached value if not expired
loading.success(format!("{} icon fetched from cache", url));
loading.end();
return Ok(cached_value.data);
return Ok(cached_value.0.data);
} else {
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Don’t panic on corrupt/old cache; handle bincode decode errors gracefully.

unwrap() on decode_from_slice will crash the process if bytes are malformed (e.g., version bump, partial writes). Treat it as a cache miss and evict.

Apply this diff:

-    let config = config::standard();
-    if let Ok(Some(entry)) = self.cache.connection().get(url) {
-      let cached_value:(CacheValue, usize) = bincode::decode_from_slice(&entry, config).unwrap();
-      if cached_value.0.expiration > SystemTime::now() {
+    let config = config::standard();
+    if let Ok(Some(entry)) = self.cache.connection().get(url) {
+      match bincode::decode_from_slice::<CacheValue, _>(&entry, config) {
+        Ok((cached_value, _)) if cached_value.expiration > SystemTime::now() => {
           // Return cached value if not expired
           loading.success(format!("{} icon fetched from cache", url));
           loading.end();
-        return Ok(cached_value.0.data);
-      } else {
-        // Remove expired cache
-        self.cache.connection().remove(url).unwrap();
-      }
+          return Ok(cached_value.data);
+        }
+        Ok((_cached_value, _)) => {
+          // Remove expired cache
+          let _ = self.cache.connection().remove(url);
+        }
+        Err(_) => {
+          // Corrupt/incompatible cache; evict
+          let _ = self.cache.connection().remove(url);
+        }
+      }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let config = config::standard();
if let Ok(Some(entry)) = self.cache.connection().get(url) {
let cached_value: CacheValue = bincode::deserialize(&entry).unwrap();
if cached_value.expiration > SystemTime::now() {
let cached_value:(CacheValue, usize) = bincode::decode_from_slice(&entry, config).unwrap();
if cached_value.0.expiration > SystemTime::now() {
// Return cached value if not expired
loading.success(format!("{} icon fetched from cache", url));
loading.end();
return Ok(cached_value.data);
return Ok(cached_value.0.data);
} else {
let config = config::standard();
if let Ok(Some(entry)) = self.cache.connection().get(url) {
match bincode::decode_from_slice::<CacheValue, _>(&entry, config) {
Ok((cached_value, _)) if cached_value.expiration > SystemTime::now() => {
// Return cached value if not expired
loading.success(format!("{} icon fetched from cache", url));
loading.end();
return Ok(cached_value.data);
}
Ok((_cached_value, _)) => {
// Remove expired cache
let _ = self.cache.connection().remove(url);
}
Err(_) => {
// Corrupt/incompatible cache; evict
let _ = self.cache.connection().remove(url);
}
}
}
🤖 Prompt for AI Agents
In rust-plugins/icons/src/cache/mod.rs around lines 27 to 35, the code currently
calls bincode::decode_from_slice(...).unwrap() which will panic on
malformed/corrupt cached bytes; change this to handle decode errors gracefully
by matching the Result returned by decode_from_slice and treating any Err as a
cache miss: log a warning about corrupt cache for the given url, evict/delete
the cache entry (call the same removal path used for expired entries), and
continue as if the entry was not present (do not return or propagate a panic);
only proceed to check expiration and return the cached data on Ok(decoded) with
a valid expiration. Ensure no unwraps remain and use safe error handling so
corrupt/old cache entries are removed and do not crash the process.

Comment on lines +4 to 11
const ComponentC: typeof import('./../components/ComponentC')['ComponentC']
const ComponentA: typeof import('./../components/ComponentA')['default']
const ComponentE: typeof import('./../components/ComponentE')['ComponentE']
const ComponentG: typeof import('./../components/ComponentE')['ComponentG']
const ComponentD: typeof import('./../components/ComponentD')['default']
const ComponentX: typeof import('./../components/ComponentD')['ComponentX']
const ComponentB: typeof import('./../components/ComponentB')['ComponentB']
const ComponentC: typeof import('./../components/ComponentC')['ComponentC']
const ComponentD: typeof import('./../components/ComponentD')['default']
const ComponentG: typeof import('./../components/ComponentE')['ComponentG']
const ComponentF: typeof import('./../components/ComponentE')['ComponentF']
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Confirm cross-file component exports (ComponentG, ComponentX).

These entries assume:

  • ComponentE exports ComponentE, ComponentF, ComponentG.
  • ComponentD exports default and named ComponentX.

Please verify to avoid ambient type drift at compile time.

Run to check files/exports:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="rust-plugins/react-components/playground/src/components"

# Resolve module files
find_mod() {
  fd -a -t f -e ts -e tsx -e js -e jsx "^$1\.(t|j)sx?$" "$base" | head -n1
}

check_named() {
  local file="$1" name="$2"
  rg -nP "export\s+(const|function|class)\s+$name\b|export\s*{\s*[^}]*\b$name\b" "$file" >/dev/null || {
    echo "MISSING named export $name in $file"
  }
}

check_default() {
  local file="$1"
  rg -nP 'export\s+default\s+' "$file" >/dev/null || {
    echo "MISSING default export in $file"
  }
}

declare -a checks=(
  "ComponentA:default"
  "ComponentB:ComponentB"
  "ComponentC:ComponentC"
  "ComponentD:default"
  "ComponentD:ComponentX"
  "ComponentE:ComponentE"
  "ComponentE:ComponentF"
  "ComponentE:ComponentG"
)

for entry in "${checks[@]}"; do
  module="${entry%%:*}"
  exportName="${entry##*:}"
  file="$(find_mod "$module" || true)"
  if [ -z "${file:-}" ]; then echo "MISSING FILE: $module.* under $base"; continue; fi
  if [ "$exportName" = "default" ]; then check_default "$file"; else check_named "$file" "$exportName"; fi
done

Length of output: 7643


Export missing named components or update type definitions

  • ComponentC.tsx doesn’t export a named ComponentC but is referenced as such in components.d.ts
  • ComponentE.tsx doesn’t export a named ComponentF but is referenced as such in components.d.ts

Add the missing named exports in those modules or adjust the type definitions to use their default exports to prevent ambient type drift.

🤖 Prompt for AI Agents
In rust-plugins/react-components/playground/src/types/components.d.ts around
lines 4 to 11, the type declarations reference named exports that don't exist
(ComponentC and ComponentF) causing ambient type drift; update the modules to
export those named components or change the type declarations to reference the
modules' default exports. Specifically either add named exports ComponentC in
src/components/ComponentC.tsx and ComponentF in src/components/ComponentE.tsx
(export const ComponentC = ... / export const ComponentF = ... or export {
ComponentC, ComponentF } as appropriate), or modify the corresponding lines in
components.d.ts to use typeof import('./../components/ComponentC')['default']
and typeof import('./../components/ComponentE')['default'] so the types match
the actual default exports.

use farmfe_plugin_react_components::Dts;
use farmfe_plugin_react_components::ImportMode;
use farmfe_plugin_react_components::{FarmPluginReactComponents, Options};
use rustc_hash::FxHashMap;
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

FxHashMap import aligns with Farm v2 types; check dev-deps.

Looks good. Ensure rustc_hash is declared for this crate (deps or dev-deps), otherwise the test won’t compile.

Run to verify:


🏁 Script executed:

#!/bin/bash
# Verify rustc_hash is declared for react-components crate
rg -n -C2 -g 'rust-plugins/react-components/**/Cargo.toml' $'^(\\[dev-dependencies\\]|\\[dependencies\\])|^\\s*rustc_hash\\s*='

Length of output: 460


Add rustc_hash to dev-dependencies
The tests in rust-plugins/react-components/tests/mod.rs use rustc_hash::FxHashMap, but rustc_hash isn’t declared in Cargo.toml. Add it under [dev-dependencies] in rust-plugins/react-components/Cargo.toml so the tests compile.

🤖 Prompt for AI Agents
In rust-plugins/react-components/tests/mod.rs around line 21, the test imports
rustc_hash::FxHashMap but rustc_hash is not declared in the crate's Cargo.toml;
open rust-plugins/react-components/Cargo.toml and add rustc_hash under the
[dev-dependencies] section (use the project/workspace preferred version or a
compatible version), save and run cargo test to confirm the tests compile.

Comment on lines +130 to 139
let transform_output_file_name_params = TransformOutputFileNameParams {
filename_config,
name: filename,
name_hash: "",
bytes: &raw_bytes,
ext,
special_placeholders: &Default::default()
};
let output_file_name = transform_output_filename(transform_output_file_name_params);
res = format!("{}{}", &public_path, &output_file_name);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid referencing a temporary Default and inline the params

&Default::default() creates a short-lived temporary; inline the struct in the call (or bind a local) to satisfy lifetimes. Also, you can reuse raw_bytes to avoid a second read below.

-      let transform_output_file_name_params = TransformOutputFileNameParams {
-        filename_config,
-        name: filename,
-        name_hash: "",
-        bytes: &raw_bytes,
-        ext,
-        special_placeholders: &Default::default()
-      };
-      let output_file_name = transform_output_filename(transform_output_file_name_params);
+      let output_file_name = transform_output_filename(TransformOutputFileNameParams {
+        filename_config,
+        name: filename,
+        name_hash: "",
+        bytes: &raw_bytes,
+        ext,
+        special_placeholders: &Default::default(),
+      });
@@
-      let content = read_file_raw(param.resolved_path).unwrap();
+      let content = raw_bytes;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let transform_output_file_name_params = TransformOutputFileNameParams {
filename_config,
name: filename,
name_hash: "",
bytes: &raw_bytes,
ext,
special_placeholders: &Default::default()
};
let output_file_name = transform_output_filename(transform_output_file_name_params);
res = format!("{}{}", &public_path, &output_file_name);
let output_file_name = transform_output_filename(TransformOutputFileNameParams {
filename_config,
name: filename,
name_hash: "",
bytes: &raw_bytes,
ext,
special_placeholders: &Default::default(),
});
res = format!("{}{}", &public_path, &output_file_name);
let content = raw_bytes;
🤖 Prompt for AI Agents
In rust-plugins/url/src/lib.rs around lines 130 to 139, avoid passing a
temporary reference &Default::default() into TransformOutputFileNameParams
(which creates a short-lived temporary and can cause lifetime issues) and stop
re-reading the file bytes; instead create a local variable let
special_placeholders = Default::default() and pass &special_placeholders to
TransformOutputFileNameParams (or inline the struct into the function call but
bind special_placeholders to a local), and reuse the already-read raw_bytes
variable for the bytes field so you don’t read the file a second time.

Comment on lines +22 to +23
"@farmfe/core": "^2.0.0-bate.0",
"@farmfe/plugin-react": "^2.0.0-bate.0",
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix version typo: "bate" → "beta".

Same prerelease misspelling as other playground; will break installs.

-    "@farmfe/core": "^2.0.0-bate.0",
-    "@farmfe/plugin-react": "^2.0.0-bate.0",
+    "@farmfe/core": "^2.0.0-beta.0",
+    "@farmfe/plugin-react": "^2.0.0-beta.0",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"@farmfe/core": "^2.0.0-bate.0",
"@farmfe/plugin-react": "^2.0.0-bate.0",
"@farmfe/core": "^2.0.0-beta.0",
"@farmfe/plugin-react": "^2.0.0-beta.0",
🤖 Prompt for AI Agents
In rust-plugins/wasm/playground/package.json around lines 22 to 23, the
prerelease tag "bate" is misspelled; replace "bate" with "beta" in the version
strings for both "@farmfe/core" and "@farmfe/plugin-react" so the dependencies
use the correct prerelease tag and installs won't fail.

Comment on lines +22 to +23
"@farmfe/core": "^2.0.0-bate.0",
"@farmfe/plugin-react": "^2.0.0-bate.0",
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix version typo: "bate" → "beta".

The prerelease tag is misspelled and will fail resolution.

-    "@farmfe/core": "^2.0.0-bate.0",
-    "@farmfe/plugin-react": "^2.0.0-bate.0",
+    "@farmfe/core": "^2.0.0-beta.0",
+    "@farmfe/plugin-react": "^2.0.0-beta.0",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"@farmfe/core": "^2.0.0-bate.0",
"@farmfe/plugin-react": "^2.0.0-bate.0",
"@farmfe/core": "^2.0.0-beta.0",
"@farmfe/plugin-react": "^2.0.0-beta.0",
🤖 Prompt for AI Agents
In rust-plugins/worker/playground/package.json around lines 22 to 23 the
prerelease tag "bate" is misspelled in the dependency versions; update both
occurrences ("^2.0.0-bate.0") to the correct prerelease tag ("^2.0.0-beta.0") so
the package resolver can match the intended beta versions.

@CCherry07 CCherry07 changed the title feat: update farm v2 feat(rust-plugins): 🎸 update farm v2-beta Sep 2, 2025
@CCherry07 CCherry07 closed this Sep 2, 2025
Copy link

@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: 4

Caution

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

⚠️ Outside diff range comments (3)
rust-plugins/worker/src/lib.rs (3)

116-132: Compute name/extension robustly and use a stable hash base.

  • split_once(".") breaks on multi-dot filenames; use Path helpers.
  • Hashing with module_id.as_bytes() makes output depend on the importer; use resolved_path (or content) for deterministic worker file names.
  • Prefer normalizing to .mjs for both .js and TS-like extensions.
-  let file_name_ext = Path::new(resolved_path)
-    .file_name()
-    .map(|x| x.to_string_lossy().to_string())
-    .unwrap_or_else(|| "".to_string());
-  let (file_name, ext) = file_name_ext.split_once(".").unwrap();
-  let assets_filename_config = compiler_config.output.assets_filename.clone();
-  let transform_output_file_name_params = TransformOutputFileNameParams {
-    filename_config: assets_filename_config,
-    name: file_name,
-    name_hash: "",
-    bytes: &module_id.as_bytes(),
-    ext,
-    special_placeholders: &Default::default(),
-  };
+  let path = Path::new(resolved_path);
+  let file_stem = path.file_stem().and_then(|s| s.to_str()).unwrap_or_default();
+  let ext = path.extension().and_then(|s| s.to_str()).unwrap_or_default();
+  let assets_filename_config = compiler_config.output.assets_filename.clone();
+  let transform_output_file_name_params = TransformOutputFileNameParams {
+    filename_config: assets_filename_config,
+    name: file_stem,
+    name_hash: "",
+    // Use resolved_path for stable, content-agnostic hashing; consider using bytes after build if content hashing is desired.
+    bytes: resolved_path.as_bytes(),
+    ext,
+    special_placeholders: &Default::default(),
+  };
   // hash_bytes = resolved_path + file_name_ext bytes ,make sure that the files of the same name in different directory will not be covered;
-  let file_name = transform_output_filename(transform_output_file_name_params);
-  // worker.ts -> worker.js
-  let file_name = if file_name.ends_with(".ts") {
-    file_name.replace(".ts", ".js")
-  } else {
-    file_name
-  };
+  let file_name = transform_output_filename(transform_output_file_name_params);
+  // Normalize to .mjs for esm workers
+  let file_name = match Path::new(&file_name).extension().and_then(|s| s.to_str()) {
+    Some("ts") | Some("tsx") | Some("mts") | Some("cts") | Some("js") => {
+      let (stem, _) = file_name.rsplit_once('.').unwrap();
+      format!("{stem}.mjs")
+    }
+    _ => file_name,
+  };

210-213: Cache key mismatch in inline mode (panic risk).

You insert/fetch with file_name elsewhere, but here you read with resolved_path. This will unwrap() on None.

-      let content_bytes = worker_cache.get(resolved_path).unwrap();
+      let content_bytes = worker_cache.get(&file_name).unwrap();

391-401: Wrong capture group for string inside new URL(...).

captures[1] spans the entire new URL(...); you then slice off quotes incorrectly. Use the inner string literal capture instead.

-      let args = &m.captures[0].clone().unwrap();
-      let worker_url = &m.captures[1].clone().unwrap();
-      let arg_code = &param.content[args.start..args.end];
-      let worker_url_code = &param.content[worker_url.start..worker_url.end];
+      let args = &m.captures[0].clone().unwrap();          // full `new Worker(...`
+      let url_cap = &m.captures[2].clone().unwrap();       // string literal inside new URL(...)
+      let arg_code = &param.content[args.start..args.end];
+      let worker_url_code = &param.content[url_cap.start..url_cap.end];
       if arg_code.contains("`") && arg_code.contains("${") {
         println!("new URL(url, import.meta.url) is not supported in dynamic template string.")
       } else {
         let compiler_config = self.options.compiler_config.as_ref().unwrap();
-        let worker_url = &worker_url_code[1..worker_url_code.len() - 1];
+        let worker_url = &worker_url_code[1..worker_url_code.len() - 1]; // strip quotes
🧹 Nitpick comments (8)
rust-plugins/worker/playground/src/index.tsx (2)

3-7: Drop committed commented-out code (or guard behind a flag).

These debug/toggle lines add noise. If you need them for local switching, wrap behind a dev flag; otherwise remove.

-// import TestWorker from "./worker/test.worker?worker"
-
-// console.log(TestWorker);
-// const worker = new TestWorker();

17-19: Mirror options and basic error handling for worker2; logging label is good.

Align instantiation with worker1 and add error hooks; the labeled log helps triage.

-const worker2 = new Worker(new URL("./worker/vue.worker.ts",import.meta.url))
+const worker2 = new Worker(new URL('./worker/vue.worker.ts', import.meta.url), { type: 'module' })
 
 worker2.postMessage([2, 3]);
 worker2.onmessage = (e) => {
   console.log('vue worker', e.data);
 }
+worker2.onerror = (err) => console.error('vue worker error', err);
+worker2.onmessageerror = (e) => console.warn('vue worker messageerror', e);
rust-plugins/compress/playground/package.json (1)

1-27: Consider declaring Node.js engine to match Farm v2 toolchain.

If v2 expects a minimum Node (e.g., >=18.18), add an engines field to prevent accidental installs on older Node.

 {
   "name": "playground",
   "version": "1.0.0",
   "type": "module",
+  "engines": {
+    "node": ">=18.18"
+  },
   "scripts": {
rust-plugins/compress/src/lib.rs (2)

96-101: Tighten regex match and avoid needless borrowing.

filter.is_match(&resource_id) adds an extra layer of referencing; pass &str directly. Also, consider short-circuiting on threshold first to avoid a regex call on small files (micro).

-        if !filter.is_match(&resource_id) || resource.bytes.len() < self.options.threshold {
+        if resource.bytes.len() < self.options.threshold || !filter.is_match(resource_id) {
           return None;
         }

136-136: Remove needless borrow in sha256 call.

Avoid &&[u8].

-          name_hash: sha256(&name.as_bytes(), 8),
+          name_hash: sha256(name.as_bytes(), 8),
rust-plugins/worker/src/lib.rs (3)

73-85: Config threading looks right; minor suggestion on input key.

Feeding full_file_name as the virtual entry key ties downstream lookups to that string. If you replace the extension later, prefer the stem as the key to reduce surprises.

-  input.insert(full_file_name.clone(), resolved_path.to_string());
+  input.insert(
+    Path::new(&full_file_name)
+      .file_stem()
+      .and_then(|s| s.to_str())
+      .unwrap_or(&full_file_name)
+      .to_string(),
+    resolved_path.to_string(),
+  );

404-417: Avoid .unwrap() chain on resolve.

Downstream panics on resolution failures are hard to debug. Propagate an error or early-return Ok(None).

-              .unwrap()
-              .unwrap()
-              .resolved_path
+              .ok_or_else(|| anyhow::anyhow!("Worker resolve failed for {worker_url}"))?
+              .ok_or_else(|| anyhow::anyhow!("Worker unresolved for {worker_url}"))?
+              .resolved_path

451-487: Cache (de)serialization with expanded Resource still compatible.

Emitting cached assets back is fine; consider logging count for observability.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 8662f4d and a63f091.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • rust-plugins/compress/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (5)
  • rust-plugins/compress/Cargo.toml (1 hunks)
  • rust-plugins/compress/playground/package.json (1 hunks)
  • rust-plugins/compress/src/lib.rs (3 hunks)
  • rust-plugins/worker/playground/src/index.tsx (1 hunks)
  • rust-plugins/worker/src/lib.rs (10 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • rust-plugins/compress/Cargo.toml
🧰 Additional context used
🧬 Code graph analysis (2)
rust-plugins/compress/src/lib.rs (1)
rust-plugins/compress/src/utils.rs (1)
  • get_ext_name (90-96)
rust-plugins/worker/src/lib.rs (1)
rust-plugins/worker/src/cache.rs (1)
  • new (10-14)
🔇 Additional comments (5)
rust-plugins/compress/src/lib.rs (1)

80-83: API alignment looks good.

PluginFinalizeResourcesHookParam update matches v2 API changes.

rust-plugins/worker/src/lib.rs (4)

171-183: Good: dedup emit via worker cache.

The up-front cache check and conditional re-emit are sound. Fixing the inline cache key will complete this path.


198-201: Format switch aligns with v2 API.

Using ModuleFormatConfig::Single(ModuleFormat::EsModule) here looks correct.


291-301: Options wiring: host_config defaulting to config.clone() is sensible.

No issues spotted.


122-132: Unify hashing base across paths.

Currently, the load-path uses module_id as hash bytes while the transform-path passes resolved_path. Pick one (recommend resolved_path) to avoid duplicate filenames for the same worker across importers.

I recommend the resolved_path.as_bytes() change proposed above; please confirm no tests rely on importer-scoped filenames.

Also applies to: 171-173, 419-425

Comment on lines 19 to +21
"@farmfe/cli": "^1.0.4",
"@farmfe/core": "^1.6.6",
"@farmfe/plugin-react": "^1.2.6",
"@farmfe/core": "^2.0.0-beta.2",
"@farmfe/plugin-react": "^2.0.0-beta.2",
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Align CLI to v2 to avoid runtime incompatibilities with Core v2.

Core and React plugin are upgraded to 2.0.0-beta.2, but CLI remains on 1.0.4. If Farm v2 requires CLI v2, farm start/build in this playground may break or use incompatible flags.

Proposed change:

   "devDependencies": {
-    "@farmfe/cli": "^1.0.4",
+    "@farmfe/cli": "^2.0.0-beta.2",
     "@farmfe/core": "^2.0.0-beta.2",
     "@farmfe/plugin-react": "^2.0.0-beta.2",

To verify consistency and availability, run:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "— Scan repo for Farm CLI/Core versions —"
fd -t f package.json | while read -r f; do
  jq -r --arg file "$f" '
    "FILE=" + $file
    + " NAME=" + (.name // "unknown")
    + " CLI=" + (.devDependencies["@farmfe/cli"] // .dependencies["@farmfe/cli"] // "N/A")
    + " CORE=" + (.devDependencies["@farmfe/core"] // .dependencies["@farmfe/core"] // "N/A")
  ' "$f"
done

echo; echo "— NPM dist-tags for @farmfe/cli and @farmfe/core —"
for pkg in cli core; do
  echo "@farmfe/$pkg dist-tags:"
  curl -s https://registry.npmjs.org/@farmfe/$pkg | jq -r '."dist-tags"'
done

Length of output: 84828


Bump CLI to available v2 pre-release

In rust-plugins/compress/playground/package.json, update the CLI to the latest v2 beta (0) since 2.0.0-beta.2 doesn’t exist:

 rust-plugins/compress/playground/package.json
   "devDependencies": {
-    "@farmfe/cli": "^1.0.4",
+    "@farmfe/cli": "^2.0.0-beta.0",
     "@farmfe/core": "^2.0.0-beta.2",
     "@farmfe/plugin-react": "^2.0.0-beta.2",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"@farmfe/cli": "^1.0.4",
"@farmfe/core": "^1.6.6",
"@farmfe/plugin-react": "^1.2.6",
"@farmfe/core": "^2.0.0-beta.2",
"@farmfe/plugin-react": "^2.0.0-beta.2",
"devDependencies": {
"@farmfe/cli": "^2.0.0-beta.0",
"@farmfe/core": "^2.0.0-beta.2",
"@farmfe/plugin-react": "^2.0.0-beta.2",
🤖 Prompt for AI Agents
In rust-plugins/compress/playground/package.json around lines 19 to 21, the
dependency "@farmfe/cli" is pinned to "^1.0.4" but the PR attempted to set it to
a non-existent "2.0.0-beta.2"; update the "@farmfe/cli" entry to the correct v2
pre-release (for example "^2.0.0-beta.0") so the package.json references an
available beta release, leaving other dependencies unchanged.

Comment on lines 127 to 128
saved += origin_file_size - bytes.len();
param.resources_map.insert(
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Fix underflow when compressed size > original.

saved is usize; origin_file_size - bytes.len() will wrap if compression inflates. Use saturating_sub (and optionally skip emitting larger artifacts).

Apply:

-      saved += origin_file_size - bytes.len();
+      let delta = origin_file_size.saturating_sub(bytes.len());
+      saved += delta;
+      // Optional: only emit if compression helps
+      // if delta == 0 { continue; }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
saved += origin_file_size - bytes.len();
param.resources_map.insert(
let delta = origin_file_size.saturating_sub(bytes.len());
saved += delta;
// Optional: only emit if compression helps
// if delta == 0 { continue; }
param.resources_map.insert(
🤖 Prompt for AI Agents
In rust-plugins/compress/src/lib.rs around lines 127-128, the code does `saved
+= origin_file_size - bytes.len()` which can underflow if the compressed size
(bytes.len()) is larger than origin_file_size; change the subtraction to use
`origin_file_size.saturating_sub(bytes.len())` (or compute a `saved_delta =
origin_file_size.saturating_sub(bytes.len())` and add that) and consider
skipping or not emitting artifacts when compressed size >= original to avoid
counting negative savings and producing larger outputs.

Comment on lines 8 to 12
const worker = new Worker(new URL("/src/worker/test.worker.ts",import.meta.url));
worker.postMessage([5, 5]);
worker.onmessage = (e) => {
console.log(e.data);
console.log('test worker', e.data);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid absolute “/src/…” in Worker URL; treat worker as ESM.

Using an absolute path ties to dev server root and can break in build/prod. Prefer relative URL and pass { type: 'module' } for ESM workers.

-const worker = new Worker(new URL("/src/worker/test.worker.ts",import.meta.url));
+const worker = new Worker(new URL('./worker/test.worker.ts', import.meta.url), { type: 'module' });
 worker.postMessage([5, 5]);
 worker.onmessage = (e) => {
   console.log('test worker', e.data);
 }
+worker.onerror = (err) => console.error('test worker error', err);
+worker.onmessageerror = (e) => console.warn('test worker messageerror', e);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const worker = new Worker(new URL("/src/worker/test.worker.ts",import.meta.url));
worker.postMessage([5, 5]);
worker.onmessage = (e) => {
console.log(e.data);
console.log('test worker', e.data);
}
const worker = new Worker(
new URL('./worker/test.worker.ts', import.meta.url),
{ type: 'module' }
);
worker.postMessage([5, 5]);
worker.onmessage = (e) => {
console.log('test worker', e.data);
}
worker.onerror = (err) => console.error('test worker error', err);
worker.onmessageerror = (e) => console.warn('test worker messageerror', e);
🤖 Prompt for AI Agents
In rust-plugins/worker/playground/src/index.tsx around lines 8 to 12, the Worker
is created with an absolute URL ("/src/...") which ties it to the dev server
root and can break in production; change the URL to a relative path (for example
"./worker/test.worker.ts" resolved against import.meta.url, i.e. new
URL("./worker/test.worker.ts", import.meta.url)) and instantiate the Worker with
the ESM option by passing { type: 'module' } as the second argument so the
worker is loaded as an ESM module.

Comment on lines +90 to 92
let resource_name = format!("{}.mjs", full_file_name);
let resource = resources_map.get(&resource_name).unwrap();
let content_bytes = resource.bytes.clone();
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Don't append .mjs to a name that may already have an extension.

format!("{}.mjs", full_file_name) risks *.js.mjs. Replace the extension instead.

-  let resource_name = format!("{}.mjs", full_file_name);
+  let resource_name = match full_file_name.rsplit_once('.') {
+    Some((stem, _)) => format!("{stem}.mjs"),
+    None => format!("{full_file_name}.mjs"),
+  };
🤖 Prompt for AI Agents
In rust-plugins/worker/src/lib.rs around lines 90 to 92, you're naively
appending ".mjs" which can produce filenames like "foo.js.mjs"; instead replace
the file extension using Path utilities: build resource_name by taking
Path::new(&full_file_name).with_extension("mjs") and converting that PathBuf
back to a String (e.g., via to_string_lossy().into_owned()), then use that
resource_name to look up the resource; this ensures existing extensions are
replaced and files without extensions get ".mjs".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants