Skip to content

Optimize dev rebuild defaults - #86

Open
ScriptedAlchemy wants to merge 10 commits into
mainfrom
codex/dev-rebuild-optimizations-20260708
Open

Optimize dev rebuild defaults#86
ScriptedAlchemy wants to merge 10 commits into
mainfrom
codex/dev-rebuild-optimizations-20260708

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Collaborator

Summary

  • stop forcing dev writeToDisk so Rsbuild keeps dev output in its memory filesystem
  • disable classic web splitChunks/runtimeChunk in dev by default while preserving user rspack optimization overrides
  • cache identical route transform results across inline/worker executors

Verification

  • pnpm test:core
  • pnpm build
  • pnpm bench:smoke
  • node scripts/bench-builds.mts --profile smoke --mode dev --iterations 1 --warmup 0 --format both --out .benchmark/results/dev-smoke
  • pnpm prettier --check src/index.ts src/parallel-route-transforms.ts tests/index.test.ts tests/features.test.ts tests/parallel-route-transforms.test.ts tests/dev-runtime.integration.test.ts
  • git diff --check

@pkg-pr-new

pkg-pr-new Bot commented Jul 8, 2026

Copy link
Copy Markdown

Open in StackBlitz

pnpm add https://pkg.pr.new/rsbuild-plugin-react-router@152af59

commit: 152af59

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Benchmark Results

Compared PR head 152af59 against base 94ed3cc.

Reading benchmark confidence

Raw deltas are always shown. The signal label only indicates whether the observed median delta is larger than a robust run-to-run noise band; it does not erase or replace the measurement.

The noise band is the larger of 2% or two combined robust standard deviations estimated from each side's relative median absolute deviation (rMAD). Fewer than three finite samples is reported as insufficient data. An inconclusive result should be rerun or investigated from the uploaded raw samples before drawing a performance conclusion.

Benchmark Runs Base total Head total Delta Base rMAD Head rMAD Noise band Signal
large-355-ssr-esm (build) 3 8.46s 8.94s +5.6% 0.3% 0.6% ±2.1% 🔴 regression
synthetic-1024-ssr-esm (build) 3 3.95s 4.76s +20.5% 0.8% 1.3% ±4.6% 🔴 regression
synthetic-1024-ssr-esm-split (build) 3 5.23s 5.98s +14.4% 0.6% 0.0% ±2.0% 🔴 regression
synthetic-256-sourcemaps (build) 5 2.21s 2.45s +11.0% 0.3% 0.9% ±3.0% 🔴 regression
synthetic-256-ssr-esm (build) 5 2.07s 2.35s +13.5% 0.3% 0.3% ±2.0% 🔴 regression
synthetic-256-ssr-esm-split (build) 5 2.47s 2.71s +9.8% 1.0% 0.8% ±3.8% 🔴 regression
synthetic-48-ssr-esm (build) 5 1.36s 1.34s -1.7% 1.5% 1.0% ±5.5% ⚪ inconclusive
large-355-ssr-esm (dev) 3 13.40s 14.07s +5.0% 0.1% 0.5% ±2.0% 🔴 regression
synthetic-1024-ssr-esm (dev) 3 4.33s 4.89s +13.0% 0.1% 0.7% ±2.2% 🔴 regression
synthetic-1024-ssr-esm-split (dev) 3 4.27s 4.85s +13.5% 0.9% 1.2% ±4.3% 🔴 regression
synthetic-256-sourcemaps (dev) 5 1.94s 2.19s +12.6% 1.2% 0.2% ±3.5% 🔴 regression
synthetic-256-ssr-esm (dev) 5 1.81s 2.04s +12.7% 0.7% 0.9% ±3.3% 🔴 regression
synthetic-256-ssr-esm-split (dev) 5 1.78s 2.02s +13.8% 1.1% 0.7% ±3.9% 🔴 regression
synthetic-48-ssr-esm (dev) 5 0.92s 0.91s -1.1% 0.7% 1.0% ±3.5% ⚪ inconclusive
complex app (cold) 3 86.53s 88.01s +1.7% 0.3% 1.1% ±3.5% ⚪ inconclusive
complex app (dev) 3 71.91s 74.01s +2.9% 0.3% 0.4% ±2.0% 🔴 regression
complex app (warm) 3 62.10s 63.25s +1.8% 0.0% 0.1% ±2.0% ⚪ inconclusive

Dev Rollup

Group Fixtures Base total Head total Delta Base ready Head ready Ready delta Base routes Head routes Route delta Base update/HMR Head update/HMR Update delta Speedup
All dev fixtures 7 28.45s 30.98s +8.9% 17.86s 20.22s +13.2% 3.80s 3.83s +0.7% 2.56s 2.46s -3.8% 0.92x
Large app 1 13.40s 14.07s +5.0% 7.37s 7.98s +8.3% 1.80s 1.86s +3.1% 1.47s 1.40s -5.1% 0.95x
Standard fixtures 6 15.06s 16.90s +12.3% 10.49s 12.23s +16.6% 2.00s 1.97s -1.5% 1.09s 1.06s -2.1% 0.89x

Production Build Benchmarks

Rendered 7 production build benchmarks.

Benchmark Runs Base total Head total Delta Head mean Head p95 Speedup Head RSS p95
large-355-ssr-esm 3 8.46s 8.94s +5.6% 8.95s 9.03s 0.95x 1536 MB
synthetic-1024-ssr-esm 3 3.95s 4.76s +20.5% 4.74s 4.82s 0.83x 713 MB
synthetic-1024-ssr-esm-split 3 5.23s 5.98s +14.4% 5.97s 5.99s 0.87x 844 MB
synthetic-256-sourcemaps 5 2.21s 2.45s +11.0% 2.44s 2.48s 0.90x 480 MB
synthetic-256-ssr-esm 5 2.07s 2.35s +13.5% 2.34s 2.37s 0.88x 440 MB
synthetic-256-ssr-esm-split 5 2.47s 2.71s +9.8% 2.71s 2.74s 0.91x 466 MB
synthetic-48-ssr-esm 5 1.36s 1.34s -1.7% 1.34s 1.38s 1.02x 295 MB

ci-small+ci-large Dev Fixture Summary

Rendered 7 dev benchmark fixtures from the ci-small+ci-large profile.

Benchmark Runs Base total Head total Delta Base ready Head ready Base routes Head routes Base update/HMR Head update/HMR Update delta Head mean Head p95 Speedup Head RSS p95
large-355-ssr-esm 3 13.40s 14.07s +5.0% 7.37s 7.98s 1.80s 1.86s 1.47s 1.40s -5.1% 14.07s 14.14s 0.95x -
synthetic-1024-ssr-esm 3 4.33s 4.89s +13.0% 2.99s 3.51s 0.57s 0.55s 0.33s 0.33s -0.1% 4.91s 4.99s 0.89x -
synthetic-1024-ssr-esm-split 3 4.27s 4.85s +13.5% 2.95s 3.50s 0.56s 0.56s 0.33s 0.33s -0.7% 4.92s 5.11s 0.88x -
synthetic-256-sourcemaps 5 1.94s 2.19s +12.6% 1.40s 1.63s 0.25s 0.25s 0.13s 0.13s +0.5% 2.19s 2.23s 0.89x -
synthetic-256-ssr-esm 5 1.81s 2.04s +12.7% 1.27s 1.49s 0.25s 0.25s 0.13s 0.13s +0.2% 2.04s 2.06s 0.89x -
synthetic-256-ssr-esm-split 5 1.78s 2.02s +13.8% 1.24s 1.46s 0.25s 0.25s 0.13s 0.11s -17.0% 2.01s 2.04s 0.88x -
synthetic-48-ssr-esm 5 0.92s 0.91s -1.1% 0.65s 0.64s 0.13s 0.12s 0.05s 0.05s +0.5% 0.90s 0.92s 1.01x -

large-355-ssr-esm Plugin Operations

Environment Operation Count Base total Head total Delta Head wall Head max Reports
web route:module 1071 1039.3ms 2879.3ms +177.0% - 34.0ms 21
node route:module 1071 490.4ms 978.9ms +99.6% - 8.0ms 30
web route:client-entry 1071 261.5ms 242.1ms -7.4% 242.1ms 5.7ms 6
node manifest:transform 3 46.9ms 56.7ms +20.9% 56.7ms 19.8ms 3
web manifest:stage 6 8.7ms 8.7ms 0.0% 8.7ms 1.9ms 6
web manifest:transform 3 0.3ms 0.3ms 0.0% 0.3ms 0.1ms 3

synthetic-1024-ssr-esm Plugin Operations

Environment Operation Count Base total Head total Delta Head wall Head max Reports
web route:module 3078 1243.3ms 2131.4ms +71.4% - 29.0ms 26
node route:module 3078 547.8ms 1053.0ms +92.2% - 9.1ms 27
web route:client-entry 3078 383.1ms 365.1ms -4.7% 365.1ms 6.4ms 6
node manifest:transform 3 124.5ms 120.5ms -3.2% 120.5ms 41.4ms 3
node module:client-only-stub 3 44.4ms 19.6ms -55.9% 19.6ms 7.8ms 3
web manifest:stage 6 29.7ms 38.9ms +31.0% 38.9ms 7.4ms 6
web manifest:transform 3 0.3ms 0.1ms -66.7% 0.1ms 0.1ms 3

synthetic-1024-ssr-esm-split Plugin Operations

Environment Operation Count Base total Head total Delta Head wall Head max Reports
web route:module 3078 1260.4ms 2171.1ms +72.3% - 42.3ms 27
node route:module 3078 555.3ms 1035.2ms +86.4% - 5.6ms 24
web route:client-entry 3078 363.9ms 388.0ms +6.6% 388.0ms 7.3ms 6
node module:client-only-stub 3 309.6ms 46.6ms -84.9% 46.6ms 35.6ms 3
node manifest:transform 3 138.0ms 118.4ms -14.2% 118.4ms 41.0ms 3
web manifest:stage 7 35.4ms 41.5ms +17.2% 41.5ms 7.6ms 7
web manifest:transform 3 0.3ms 0.3ms 0.0% 0.3ms 0.1ms 3

synthetic-256-sourcemaps Plugin Operations

Environment Operation Count Base total Head total Delta Head wall Head max Reports
web route:module 1290 717.0ms 1804.8ms +151.7% - 22.3ms 20
node route:module 1290 313.0ms 679.8ms +117.2% - 7.5ms 32
web route:client-entry 1290 208.9ms 203.5ms -2.6% 203.5ms 4.8ms 10
node module:client-only-stub 5 204.5ms 34.5ms -83.1% 34.5ms 10.3ms 5
node manifest:transform 5 80.4ms 83.0ms +3.2% 83.0ms 19.6ms 5
web manifest:stage 10 11.2ms 9.9ms -11.6% 9.9ms 1.3ms 10
web manifest:transform 5 0.5ms 0.5ms 0.0% 0.5ms 0.1ms 5

synthetic-256-ssr-esm Plugin Operations

Environment Operation Count Base total Head total Delta Head wall Head max Reports
web route:module 1291 697.1ms 1522.1ms +118.3% - 16.9ms 21
node route:module 1290 272.9ms 551.8ms +102.2% - 4.3ms 32
web route:client-entry 1291 203.4ms 216.6ms +6.5% 216.6ms 6.3ms 11
node manifest:transform 5 70.2ms 90.1ms +28.3% 90.1ms 20.5ms 5
web manifest:stage 11 11.1ms 11.1ms 0.0% 11.1ms 1.4ms 11
node module:client-only-stub 5 10.2ms 59.2ms +480.4% 59.2ms 24.0ms 5
web manifest:transform 5 0.5ms 0.5ms 0.0% 0.5ms 0.1ms 5

synthetic-256-ssr-esm-split Plugin Operations

Environment Operation Count Base total Head total Delta Head wall Head max Reports
web route:module 1293 671.2ms 1511.8ms +125.2% - 16.6ms 23
node route:module 1290 287.4ms 544.2ms +89.4% - 5.0ms 35
web route:client-entry 1293 202.8ms 204.6ms +0.9% 204.6ms 5.1ms 13
node manifest:transform 5 77.4ms 69.3ms -10.5% 69.3ms 17.0ms 5
node module:client-only-stub 5 23.6ms 38.6ms +63.6% 38.6ms 12.3ms 5
web manifest:stage 13 10.5ms 12.8ms +21.9% 12.8ms 1.3ms 13
web manifest:transform 5 0.5ms 0.5ms 0.0% 0.5ms 0.1ms 5

synthetic-48-ssr-esm Plugin Operations

Environment Operation Count Base total Head total Delta Head wall Head max Reports
web route:module 250 228.0ms 203.3ms -10.8% - 13.9ms 10
node route:module 250 86.6ms 80.9ms -6.6% - 0.6ms 10
web route:client-entry 250 59.9ms 53.2ms -11.2% 53.2ms 3.3ms 10
node module:client-only-stub 5 51.7ms 40.5ms -21.7% 40.5ms 10.3ms 5
node manifest:transform 5 24.5ms 29.3ms +19.6% 29.3ms 6.4ms 5
web manifest:stage 10 2.9ms 2.6ms -10.3% 2.6ms 0.4ms 10
web manifest:transform 5 0.5ms 0.5ms 0.0% 0.5ms 0.1ms 5

Synthetic Rsbuild App

Rendered 2 production build benchmarks.

Benchmark Runs Base total Head total Delta Head mean Head p95 Speedup Head RSS p95
complex app 3 86.53s 88.01s +1.7% 87.99s - 0.98x -
complex app 3 62.10s 63.25s +1.8% 62.87s - 0.98x -

Rendered 1 dev benchmark fixture from the embedded complex app.

Benchmark Runs Base total Head total Delta Base ready Head ready Base routes Head routes Base update/HMR Head update/HMR Update delta Head mean Head p95 Speedup Head RSS p95
complex app 3 71.91s 74.01s +2.9% 64.61s 67.13s 2.31s 2.22s 1.80s 1.80s +0.1% 73.87s - 0.97x -

Profile: ci-small+ci-large; mode: dev; iterations: 5; warmup: 1.
The uploaded benchmark artifact includes diagnostics/summary.md and diagnostics/summary.json with runner metadata, per-run timing samples, CPU/RSS samples, and plugin timing hot spots.
Workflow run

@ScriptedAlchemy
ScriptedAlchemy force-pushed the codex/dev-rebuild-optimizations-20260708 branch from 5b459a4 to d09dfb1 Compare July 8, 2026 20:50
@matthewdavis-oai

Copy link
Copy Markdown
Contributor

The current PR description appears stale in two places: the head keeps runtimeChunk: 'single' and does not force splitChunks: false, and the worker/executor result-cache path has been replaced by the dev Rspack loader plus the production API-transform path.

The latest CI comparison is still useful evidence for this work: update/HMR improves from 2.92 s to 2.63 s (-10.1%) across the seven dev fixtures, 1.72 s to 1.55 s (-9.9%) on the large fixture, and 3.37 s to 2.43 s (-27.9%) on the complex synthetic app. Ready time and several standard-fixture totals regress (all-fixture ready 19.60 s to 21.15 s, +7.9%), with route:module attribution increasing substantially in the larger cases. Calling out both results would make the performance/correctness handoff clearer.

The removal of forced dev.writeToDisk: true is present and preserves an explicit user setting, which is the relevant memory-filesystem/HMR fix.

@matthewdavis-oai

matthewdavis-oai commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

One correctness gap in the installed-package development path is worth covering before this lands: route-module-transform-loader calls executeRouteTransformTask({ kind: 'routeModule', ... }) without devHmr, while the API-transform path supplies the computed development-HMR value. route-transform-tasks only appends missing $RefreshReg$ registrations for already-lowered JSX/MDX when that value is enabled. A route can therefore remount and lose state after an update even though the source-test/API path passes.

A focused fix would thread the computed web React-Refresh/HMR-enabled value into the loader rule/options (or derive the same value from loader compiler options), forward it to the task, and add a loader-path regression using already-lowered JSX that asserts $RefreshReg$ plus a state-preserving update. The current RSTEST API-transform fallback and loader tests do not exercise that boundary.

There is also a source-map correctness gap: the new loader is enforce: 'post', so preceding MDX/SWC/other loaders can pass transformed source and an incoming map. The loader accepts only source and returns a newly generated map, replacing rather than composing the incoming mapping. That can point devtools at the wrong original route lines/columns. Accept and compose inputSourceMap (or use a map-aware transform path) and add a two-loader regression that verifies traced original positions, not merely that a map exists.

Finally, the loader's performance-profiler map/timer is process-local. With parallel loader workers, each worker aggregates its own route:module samples, so the reported operation totals are not one compiler/environment-wide aggregate. Either merge reports in a coordinator/compiler hook or explicitly label them per worker and add a multi-worker attribution assertion; the current two-call test covers only a single thread.

One option-semantics caveat for the description/benchmark output: production now always selects the API-transform path and its runner is inline, so parallelRouteTransform: true | number has no production effect even though benchmark output can still display maxWorkers. Document the option as development-only (and mark it ignored in build reporting), or retain a supported parallel build path; a config/action regression would prevent the silent mismatch.

@ScriptedAlchemy
ScriptedAlchemy marked this pull request as ready for review July 28, 2026 01:05

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9e126dc301

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +53 to +57
const parallel = getRouteModuleTransformParallel(parallelRouteTransform);
return {
loader: routeModuleTransformLoaderPath,
options,
...(parallel ? { parallel } : {}),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Gate the parallel loader on the declared Rsbuild range

When parallelRouteTransform is enabled explicitly, or automatically for 256+ routes, this emits Rspack's new parallel loader option unconditionally. The package still declares @rsbuild/core: ^2.0.0 as a peer, although this commit needed to upgrade its own toolchain to Rsbuild 2.1.5/Rspack 2.1.3 for this API; consumers on an accepted older peer version will therefore reject the rule during configuration instead of building. Raise the peer minimum or feature-detect this capability and fall back to a non-parallel loader.

Useful? React with 👍 / 👎.

Comment thread src/types.ts
Comment on lines +60 to +63
* Run route module transforms with Rspack's parallel loader workers.
* Pass `true` to use Rspack's default worker count, a positive integer to set
* the maximum worker count, or `false` to disable.
* @default Automatically enabled for 256+ resolved routes.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Update the public README with the new worker semantics

These public option semantics now delegate true to Rspack's default worker count and treat a number as a maximum, but README.md:87 still promises that development uses zero workers on machines with four or fewer cores and describes a number as the worker count. Users following the published README can consequently enable workers in environments where they expected inline transforms and see unexpected resource usage; update the README alongside this API change.

Useful? React with 👍 / 👎.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The route transformation pipeline now uses a Rspack loader and task runner instead of the previous worker executor. New rule registration handles route queries, route paths, source maps, performance reporting, and configurable parallel workers. Build and development wiring was updated, federation async startup was enabled, benchmark reporting gained worker metadata, and dependencies were upgraded. Tests cover loader behavior, transform rules, integration behavior, federation configuration, performance aggregation, and benchmark summaries.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and matches the main theme of the PR: improving development rebuild defaults.
Description check ✅ Passed The description is clearly related to the changeset and summarizes the dev-output and route-transform updates.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/dev-rebuild-optimizations-20260708

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/federation.ts`:
- Around line 20-27: Update the pluginName check in the federation plugin
detection flow to accept both the legacy “ModuleFederationPlugin” name and the
enhanced Rspack “RspackModuleFederationPlugin” name, while preserving the
existing option extraction. Add coverage for both plugin names, including the
enhanced constructor variant, and verify each enables experiments.asyncStartup.

In `@src/index.ts`:
- Around line 408-412: Update the route transform execution around
parallelRouteTransform and routeTransformRunner so useApiRouteModuleTransforms
mode also honors the configured parallelRouteTransform setting. Route API
transforms through the parallel task runner when enabled, or explicitly enforce
loader-only applicability for the option and preserve that contract consistently
at the additional referenced call site.

In `@tests/dev-runtime.integration.test.ts`:
- Around line 464-466: Update the hasDiskOutput assertion in the relevant
integration test to check build/client/virtual/react-router/browser-manifest.js,
removing the static/js segments so it validates the actual emitted
browser-manifest location.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: db524a5f-4104-4e2b-9bb1-30f181c3abd4

📥 Commits

Reviewing files that changed from the base of the PR and between 94ed3cc and 9e126dc.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (34)
  • benchmarks/synthetic-web-bundler-benchmark/package.json
  • config/package.json
  • examples/client-only/package.json
  • examples/cloudflare/package.json
  • examples/custom-node-server/package.json
  • examples/default-template/package.json
  • examples/epic-stack/package.json
  • examples/federation/epic-stack-remote/package.json
  • examples/federation/epic-stack/package.json
  • examples/prerender/package.json
  • examples/spa-mode/package.json
  • package.json
  • rslib.config.ts
  • scripts/benchmark/results.mts
  • src/build-output-transforms.ts
  • src/dev-background-resources.ts
  • src/federation.ts
  • src/index.ts
  • src/parallel-route-transform-protocol.ts
  • src/parallel-route-transform-worker.ts
  • src/parallel-route-transforms.ts
  • src/performance.ts
  • src/route-module-transform-loader.ts
  • src/route-module-transform-rules.ts
  • src/route-transform-tasks.ts
  • src/types.ts
  • tests/benchmark-results.test.ts
  • tests/build-output-transforms.test.ts
  • tests/dev-runtime.integration.test.ts
  • tests/federation.test.ts
  • tests/index.test.ts
  • tests/parallel-route-transforms.test.ts
  • tests/route-module-transform-loader.test.ts
  • tests/route-module-transform-rules.test.ts
💤 Files with no reviewable changes (4)
  • src/parallel-route-transform-worker.ts
  • src/parallel-route-transform-protocol.ts
  • tests/parallel-route-transforms.test.ts
  • src/parallel-route-transforms.ts

Comment thread src/federation.ts Outdated
Comment on lines +20 to +27
const pluginName = (plugin as ModuleFederationPluginLike).name;
if (pluginName !== 'ModuleFederationPlugin') {
continue;
}

const pluginOptions =
(plugin as ModuleFederationPluginLike)._options ??
(plugin as ModuleFederationPluginLike).options;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate federation.ts =="
fd -a 'federation\.ts$' . || true

echo "== file excerpt =="
if [ -f src/federation.ts ]; then
  nl -ba src/federation.ts | sed -n '1,140p'
fi

echo "== related federation symbols =="
rg -n "ensureFederationAsyncStartup|RspackModuleFederationPlugin|ModuleFederationPlugin|asyncStartup|_options|options" -S . --glob '!node_modules' --glob '!dist' --glob '!build' || true

Repository: rstackjs/rsbuild-plugin-react-router

Length of output: 456


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file excerpt =="
if [ -f src/federation.ts ]; then
  awk '{printf "%6d\t%s\n", NR, $0}' src/federation.ts | sed -n '1,160p'
fi

echo "== related federation symbols =="
rg -n "ensureFederationAsyncStartup|`@rspack/`|RspackModuleFederationPlugin|ModuleFederationPlugin|asyncStartup|mangleInternalNames|_options|options" -S . --glob '!node_modules' --glob '!dist' --glob '!build' || true

echo "== package hints =="
for f in package.json pnpm-lock.yaml yarn.lock package-lock.json; do
  [ -f "$f" ] && { echo "--- $f ---"; sed -n '1,220p' "$f"; }
done

Repository: rstackjs/rsbuild-plugin-react-router

Length of output: 50392


🌐 Web query:

@module-federation/extended rspack ModuleFederationPlugin construction plugin name RspackModuleFederationPlugin

💡 Result:

In the ecosystem of Rspack and Module Federation, the term RspackModuleFederationPlugin is not a standard export name for the primary Module Federation plugin [1][2]. Instead, you should use the ModuleFederationPlugin class, which is exported by the relevant packages depending on your required feature set [3][4]. For Rspack, there are two primary ways to implement Module Federation: 1. Using the built-in Rspack plugin: If you are using the native Module Federation capabilities built into Rspack, you import the plugin directly from Rspack's container namespace [1][4]: import { rspack } from '@rspack/core'; // Inside your plugins array new rspack.container.ModuleFederationPlugin({ // options }) 2. Using the @module-federation/enhanced package: For advanced features (often referred to as Module Federation v2.0), such as dynamic TypeScript type hints, improved runtime plugins, and better tree shaking for shared dependencies, you use the @module-federation/enhanced package [2][3][4]. The plugin is imported specifically for Rspack from this package [3][4]: import { ModuleFederationPlugin } from '@module-federation/enhanced/rspack'; // Inside your plugins array new ModuleFederationPlugin({ // options }) Regarding the name of the plugin class, the internal identifier (often used for logging or duplicate registration checks) is defined as PLUGIN_NAME within the source code of the @module-federation/core repository, but this is not the class name you use in your configuration [5]. Always refer to the class as ModuleFederationPlugin as shown above [3][4].

Citations:


🌐 Web query:

@module-federation/enhanced rspack ModuleFederationPlugin construction plugin name RspackModuleFederationPlugin

💡 Result:

When using Module Federation with Rspack, particularly the modern implementation provided by the @module-federation/enhanced package, the relevant plugin is typically imported from @module-federation/enhanced/rspack [1]. Regarding your specific query about the construction of the plugin and the name RspackModuleFederationPlugin: 1. Plugin Class and Name: In the source code of the @module-federation/core repository, specifically within the package that provides Rspack integration, the class exported as ModuleFederationPlugin explicitly defines its internal name property as RspackModuleFederationPlugin [2]. This internal name is used by the plugin for logging, hook identification, and internal referencing during the build process [2]. 2. Usage: Users generally do not construct or reference RspackModuleFederationPlugin directly by that name in their configuration files. Instead, they import the ModuleFederationPlugin class from the @module-federation/enhanced/rspack entry point [1][3]. Example of standard construction: import { ModuleFederationPlugin } from '@module-federation/enhanced/rspack'; export default { plugins: [ new ModuleFederationPlugin({ // options }), ], }; 3. Context: While the class instance is named internally as RspackModuleFederationPlugin, it serves as the interface for Module Federation v2.0 (and 1.5 features) within Rspack, providing capabilities such as runtime plugins and improved tree shaking for shared dependencies [1]. Rspack also provides a built-in ModuleFederationPlugin (available via rspack.container.ModuleFederationPlugin) which implements Module Federation 1.5, and a legacy ModuleFederationPluginV1 [4][1][5].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== tests/federation.test.ts =="
if [ -f tests/federation.test.ts ]; then
  awk '{printf "%6d\t%s\n", NR, $0}' tests/federation.test.ts
fi

echo "== fetch `@module-federation/enhanced` rspack source for Plugin name =="
node - <<'JS'
const https = require('https');
const url = 'https://unpkg.com/@module-federation/enhanced@2.5.1/dist/rspack/esm/ModuleFederationPlugin.js';
https.get(url, (res) => {
  let data = '';
  res.on('data', chunk => data += chunk);
  res.on('end', () => {
    const lines = data.split(/\r?\n/).filter(line =>
      /class\s+ModuleFederationPlugin|static\s*#(?<name>|NAME|PLUGIN_NAME)|(?<name>name|constructor\.name|PLUGIN_NAME)\s*:|constructor?/
        .test(line)
    );
    for (let i = 0; i < Math.min(lines.length, 120); i++) console.log(`${i+1} ${lines[i]}`);
  });
}).on('error', e => {
  console.error(e.message);
  process.exit(1);
});
JS

echo "== fetch `@module-federation/rspack` source for legacy plugin constructor/name =="
node - <<'JS'
const https = require('https');
const url = 'https://unpkg.com/@module-federation/rspack@0.21.6/dist/plugin.esm.mjs';
https.get(url, (res) => {
  let data = '';
  res.on('data', chunk => data += chunk);
  res.on('end', () => {
    const lines = data.split(/\r?\n/).filter(line =>
      /class\s+ModuleFederationPlugin|Name|name|constructor|PLUGIN_NAME|rspack/i
        .test(line)
    );
    for (let i = 0; i < Math.min(lines.length, 120); i++) console.log(`${i+1} ${lines[i]}`);
  });
}).on('error', e => {
  console.error(e.message);
  process.exit(1);
});
JS

echo "== deterministic probe of current selector =="
node - <<'JS'
function selects(plugin) {
  const pluginName = plugin.name;
  return pluginName === 'ModuleFederationPlugin';
}
const legacy = {
  name: 'ModuleFederationPlugin',
  options: { experiments: { asyncStartup: false } }
};
const enhanced = {
  name: 'RspackModuleFederationPlugin',
  options: { experiments: { asyncStartup: false } }
};
console.log(JSON.stringify({ legacySelected: selects(legacy), enhancedSelected: selects(enhanced), enhancedName: enhanced.name, enhancedConstructorName: enhanced.constructor?.name }));
JS

Repository: rstackjs/rsbuild-plugin-react-router

Length of output: 2901


Match Rspack federation plugins by their actual plugin name.

@module-federation/enhanced/rspack’s ModuleFederationPlugin sets plugin.name = 'RspackModuleFederationPlugin', so this exact check keeps the enhanced examples from enabling experiments.asyncStartup. Add coverage for both the legacy ModuleFederationPlugin and the enhanced plugin name/constructor variant.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/federation.ts` around lines 20 - 27, Update the pluginName check in the
federation plugin detection flow to accept both the legacy
“ModuleFederationPlugin” name and the enhanced Rspack
“RspackModuleFederationPlugin” name, while preserving the existing option
extraction. Add coverage for both plugin names, including the enhanced
constructor variant, and verify each enables experiments.asyncStartup.

Comment thread src/index.ts
Comment on lines +464 to +466
harness.hasDiskOutput(
'build/client/static/js/virtual/react-router/browser-manifest.js'
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Check the emitted browser-manifest path.

[name].js emits this entry at build/client/virtual/react-router/browser-manifest.js; the extra static/js makes this assertion pass even if the manifest is written to disk.

Proposed fix
-      'build/client/static/js/virtual/react-router/browser-manifest.js'
+      'build/client/virtual/react-router/browser-manifest.js'
📝 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
harness.hasDiskOutput(
'build/client/static/js/virtual/react-router/browser-manifest.js'
)
harness.hasDiskOutput(
'build/client/virtual/react-router/browser-manifest.js'
)
🧰 Tools
🪛 ast-grep (0.44.1)

[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { spawn } from 'node:child_process';
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(detect-child-process-typescript)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/dev-runtime.integration.test.ts` around lines 464 - 466, Update the
hasDiskOutput assertion in the relevant integration test to check
build/client/virtual/react-router/browser-manifest.js, removing the static/js
segments so it validates the actual emitted browser-manifest location.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
src/route-module-transform-rules.ts (1)

24-42: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Do not silently ignore parallelRouteTransform on the API path.

This helper only configures the loader rules, but src/index.ts bypasses those rules whenever shouldUseRouteModuleTransformApi() is true. As a result, the option has no effect on the inline/API path, including production. Preserve parallelism there or explicitly document and validate this option as development-only.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/route-module-transform-rules.ts` around lines 24 - 42, The
parallelRouteTransform option is ignored when shouldUseRouteModuleTransformApi()
selects the inline/API path. Update the API-path implementation in the
surrounding route-module transform flow to preserve the configured boolean or
worker-count parallelism, including production; otherwise explicitly reject
non-default values with validation and document the development-only constraint.
🧹 Nitpick comments (1)
tests/route-module-transform-rules.test.ts (1)

48-63: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover both positive API-selection branches.

This test only proves the negative case. Add cases for existsSync === true and RSTEST === 'true'; otherwise regressions in the loader/API dispatch can go undetected.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/route-module-transform-rules.test.ts` around lines 48 - 63, Expand the
route-module transform API tests around shouldUseRouteModuleTransformApi to
cover both positive selection branches: mock fs.existsSync to return true with
RSTEST unset, and set RSTEST to 'true' with existsSync false. Assert the
function returns true in each case, while preserving environment restoration and
spy cleanup.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/route-module-transform-rules.ts`:
- Around line 24-42: The parallelRouteTransform option is ignored when
shouldUseRouteModuleTransformApi() selects the inline/API path. Update the
API-path implementation in the surrounding route-module transform flow to
preserve the configured boolean or worker-count parallelism, including
production; otherwise explicitly reject non-default values with validation and
document the development-only constraint.

---

Nitpick comments:
In `@tests/route-module-transform-rules.test.ts`:
- Around line 48-63: Expand the route-module transform API tests around
shouldUseRouteModuleTransformApi to cover both positive selection branches: mock
fs.existsSync to return true with RSTEST unset, and set RSTEST to 'true' with
existsSync false. Assert the function returns true in each case, while
preserving environment restoration and spy cleanup.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e8e26ad3-a392-47a5-97aa-555a5ef8b41b

📥 Commits

Reviewing files that changed from the base of the PR and between 9e126dc and 152af59.

📒 Files selected for processing (11)
  • scripts/benchmark/results.mts
  • src/build-output-transforms.ts
  • src/federation.ts
  • src/index.ts
  • src/route-module-transform-loader.ts
  • src/route-module-transform-rules.ts
  • tests/benchmark-results.test.ts
  • tests/build-output-transforms.test.ts
  • tests/dev-runtime.integration.test.ts
  • tests/route-module-transform-loader.test.ts
  • tests/route-module-transform-rules.test.ts
💤 Files with no reviewable changes (1)
  • tests/dev-runtime.integration.test.ts
🚧 Files skipped from review as they are similar to previous changes (7)
  • tests/benchmark-results.test.ts
  • scripts/benchmark/results.mts
  • tests/route-module-transform-loader.test.ts
  • src/route-module-transform-loader.ts
  • src/build-output-transforms.ts
  • src/index.ts
  • tests/build-output-transforms.test.ts

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