Skip to content

feat: builtin react server component#12012

Merged
hardfist merged 99 commits intomainfrom
react-server-component
Jan 23, 2026
Merged

feat: builtin react server component#12012
hardfist merged 99 commits intomainfrom
react-server-component

Conversation

@SyMind
Copy link
Member

@SyMind SyMind commented Oct 28, 2025

Summary

This PR adds built-in RSC plugins to Rspack. We recommend using them via the Rsbuild plugin wrapper available at https://github.com/rstackjs/rsbuild-plugin-rsc.

For usage examples, please refer to: https://github.com/rstackjs/rsbuild-plugin-rsc/tree/main/examples

The builtin:swc-loader has been enhanced to identify "use client" and "use server" directives. Within the RSC layer, it utilizes the react-server-dom-rspack package to transform these modules into the appropriate client and server references required by React.

  • Note: This feature must be enabled via rspackExperiments.reactServerComponents.

RSC requires separate compilation for Server and Client bundles. This PR introduces ServerPlugin and ClientPlugin (created via rsc.createPlugins()), which orchestrate the two compilers to:

  • Collect and compile modules with RSC directives.
  • Generate the necessary manifests used by the RSC runtime.

The ServerPlugin includes an onServerComponentChanges callback. This is triggered whenever the Server Compiler detects changes in a Server Component.

Related links

Checklist

  • Tests updated (or not required).
  • Documentation updated (or not required).

@netlify
Copy link

netlify bot commented Oct 28, 2025

Deploy Preview for rspack canceled.

Name Link
🔨 Latest commit ba1ce5f
🔍 Latest deploy log https://app.netlify.com/projects/rspack/deploys/695f56cc1725660008df6843

@github-actions github-actions bot added release: feature release: feature related release(mr only) team The issue/pr is created by the member of Rspack. labels Oct 28, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Oct 28, 2025

📦 Binary Size-limit

Comparing 4276a07 to fix(template): add @rspack/dev-server to dev dependencies (#12821) by harpsealjs

❌ Size increased by 479.63KB from 47.70MB to 48.17MB (⬆️0.98%)

@codspeed-hq
Copy link

codspeed-hq bot commented Oct 28, 2025

CodSpeed Performance Report

Merging this PR will not alter performance

Comparing react-server-component (4276a07) with main (8931e11)

Summary

✅ 16 untouched benchmarks
⏩ 1 skipped benchmark1

Footnotes

  1. 1 benchmark was skipped, so the baseline result was used instead. If it was deleted from the codebase, click here and archive it to remove it from the performance reports.

@SyMind SyMind force-pushed the react-server-component branch from 948b3e2 to cedca6d Compare November 26, 2025 08:27
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Jan 22, 2026

Deploying rspack-v2 with  Cloudflare Pages  Cloudflare Pages

Latest commit: 0cfbe8e
Status: ✅  Deploy successful!
Preview URL: https://c91a7800.rspack-v2.pages.dev
Branch Preview URL: https://react-server-component.rspack-v2.pages.dev

View logs

@SyMind SyMind force-pushed the react-server-component branch 3 times, most recently from db8125e to 626f6fd Compare January 22, 2026 03:10
@SyMind SyMind force-pushed the react-server-component branch from 626f6fd to 40268c3 Compare January 22, 2026 03:17
@github-actions
Copy link
Contributor

github-actions bot commented Jan 22, 2026

📝 Benchmark detail: Open

Name Base (2026-01-22 e31ee70) Current Change
10000_big_production-mode_disable-minimize + exec 23 s ± 213 ms 23 s ± 223 ms +0.13 %
10000_development-mode + exec 1.28 s ± 13 ms 1.53 s ± 36 ms +19.62 %
10000_development-mode_hmr + stats 233 ms ± 2.9 ms 269 ms ± 4.1 ms +15.40 %
10000_development-mode_noop-loader + exec 2.24 s ± 60 ms 2.64 s ± 37 ms +17.55 %
10000_production-mode + exec 1.33 s ± 46 ms 1.61 s ± 41 ms +20.93 %
10000_production-mode_persistent-cold + exec 1.51 s ± 55 ms 1.62 s ± 40 ms +7.32 %
10000_production-mode_persistent-hot + exec 1.05 s ± 34 ms 1.61 s ± 26 ms +53.48 %
arco-pro_development-mode + exec 1.6 s ± 123 ms 1.49 s ± 55 ms -7.43 %
arco-pro_development-mode_hmr + stats 39 ms ± 1.4 ms 38 ms ± 0.79 ms -2.19 %
arco-pro_production-mode + exec 3.02 s ± 116 ms 2.83 s ± 168 ms -6.31 %
arco-pro_production-mode_generate-package-json-webpack-plugin + exec 3.14 s ± 16 ms 2.95 s ± 81 ms -5.99 %
arco-pro_production-mode_persistent-cold + exec 3.1 s ± 96 ms 2.81 s ± 48 ms -9.41 %
arco-pro_production-mode_persistent-hot + exec 1.72 s ± 46 ms 2.8 s ± 53 ms +62.59 %
arco-pro_production-mode_traverse-chunk-modules + exec 3.05 s ± 131 ms 2.86 s ± 71 ms -6.28 %
large-dyn-imports_development-mode + exec 1.56 s ± 30 ms 1.54 s ± 26 ms -1.22 %
large-dyn-imports_production-mode + exec 1.73 s ± 26 ms 1.74 s ± 23 ms +0.31 %
threejs_development-mode_10x + exec 1.28 s ± 25 ms 1.28 s ± 34 ms +0.27 %
threejs_development-mode_10x_hmr + stats 207 ms ± 3.2 ms 205 ms ± 5.1 ms -1.24 %
threejs_production-mode_10x + exec 4.06 s ± 43 ms 4.05 s ± 18 ms -0.19 %
threejs_production-mode_10x_persistent-cold + exec 4.2 s ± 27 ms 4.12 s ± 42 ms -1.84 %
threejs_production-mode_10x_persistent-hot + exec 3.62 s ± 49 ms 4.11 s ± 27 ms +13.62 %
10000_big_production-mode_disable-minimize + rss memory 5829 MiB ± 46.5 MiB 5913 MiB ± 124 MiB +1.43 %
10000_development-mode + rss memory 614 MiB ± 27.7 MiB 733 MiB ± 37.6 MiB +19.40 %
10000_development-mode_hmr + rss memory 769 MiB ± 20.2 MiB 891 MiB ± 26.9 MiB +15.82 %
10000_development-mode_noop-loader + rss memory 917 MiB ± 30.8 MiB 1054 MiB ± 32.4 MiB +15.00 %
10000_production-mode + rss memory 646 MiB ± 31.3 MiB 758 MiB ± 32.6 MiB +17.40 %
10000_production-mode_persistent-cold + rss memory 785 MiB ± 25.4 MiB 720 MiB ± 48 MiB -8.17 %
10000_production-mode_persistent-hot + rss memory 750 MiB ± 20.1 MiB 719 MiB ± 37.5 MiB -4.23 %
arco-pro_development-mode + rss memory 559 MiB ± 53.2 MiB 594 MiB ± 39.5 MiB +6.32 %
arco-pro_development-mode_hmr + rss memory 459 MiB ± 13.4 MiB 486 MiB ± 12.1 MiB +5.82 %
arco-pro_production-mode + rss memory 688 MiB ± 89.2 MiB 697 MiB ± 64.9 MiB +1.38 %
arco-pro_production-mode_generate-package-json-webpack-plugin + rss memory 662 MiB ± 29.8 MiB 715 MiB ± 67.2 MiB +8.00 %
arco-pro_production-mode_persistent-cold + rss memory 755 MiB ± 35 MiB 706 MiB ± 106 MiB -6.52 %
arco-pro_production-mode_persistent-hot + rss memory 565 MiB ± 75.5 MiB 712 MiB ± 90.7 MiB +26.05 %
arco-pro_production-mode_traverse-chunk-modules + rss memory 667 MiB ± 77 MiB 740 MiB ± 53.4 MiB +10.92 %
large-dyn-imports_development-mode + rss memory 650 MiB ± 8.98 MiB 653 MiB ± 8.17 MiB +0.39 %
large-dyn-imports_production-mode + rss memory 564 MiB ± 18.5 MiB 554 MiB ± 8.38 MiB -1.66 %
threejs_development-mode_10x + rss memory 597 MiB ± 34.2 MiB 595 MiB ± 42 MiB -0.33 %
threejs_development-mode_10x_hmr + rss memory 812 MiB ± 28.4 MiB 818 MiB ± 11.8 MiB +0.82 %
threejs_production-mode_10x + rss memory 722 MiB ± 137 MiB 740 MiB ± 124 MiB +2.41 %
threejs_production-mode_10x_persistent-cold + rss memory 836 MiB ± 36.5 MiB 751 MiB ± 177 MiB -10.16 %
threejs_production-mode_10x_persistent-hot + rss memory 675 MiB ± 17.3 MiB 792 MiB ± 147 MiB +17.29 %

Threshold exceeded: ["10000_development-mode + exec","10000_development-mode_noop-loader + exec","10000_production-mode + exec","10000_production-mode_persistent-cold + exec","10000_production-mode_persistent-hot + exec","arco-pro_production-mode_persistent-hot + exec","threejs_production-mode_10x_persistent-hot + exec"]

@hardfist
Copy link
Contributor

is the codspeed performance regression expected or just flaky?

@SyMind
Copy link
Member Author

SyMind commented Jan 22, 2026

is the codspeed performance regression expected or just flaky?
@hardfist just flaky

@SyMind SyMind changed the base branch from v2 to main January 22, 2026 10:55
Copilot AI review requested due to automatic review settings January 23, 2026 07:51
@cloudflare-workers-and-pages
Copy link

Deploying rspack with  Cloudflare Pages  Cloudflare Pages

Latest commit: 4276a07
Status: ✅  Deploy successful!
Preview URL: https://d994fc02.rspack-v2.pages.dev
Branch Preview URL: https://react-server-component.rspack-v2.pages.dev

View logs

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces first-class React Server Components (RSC) support into Rspack by wiring together compiler/runtime coordination, SWC transforms, and public plugin APIs, with an accompanying Rust plugin crate and Node bindings.

Changes:

  • Adds a new rspack_plugin_rsc crate implementing server/client RSC plugins, a manifest runtime module, loaders, hot-reload tracking, and coordination between server/client compilers.
  • Integrates RSC support into the JS/TS surface: exports experiments.rsc, wires the builtin plugins through @rspack/binding, adds SWC loader options (rspackExperiments.reactServerComponents), and extends runtime globals and compiler hooks.
  • Adjusts core compiler/watch infrastructure (new CompilerDone/CompilerFailed hooks, updated Watching dependency handling) and SWC/Javascript compiler plumbing to support the new RSC transforms and metadata.

Reviewed changes

Copilot reviewed 58 out of 61 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
packages/rspack/src/exports.ts Exposes the new rsc builtin via experiments.rsc so RSC plugins can be accessed from the JS API.
packages/rspack/src/builtin-plugin/rsc/index.ts Defines the high-level rsc helper (plugin factory + layer constants) wrapping the client/server RSC builtin plugins.
packages/rspack/src/builtin-plugin/rsc/RscServerPlugin.ts JS wrapper around the native RscServerPlugin, connecting the Coordinator binding into the builtin-plugin framework.
packages/rspack/src/builtin-plugin/rsc/RscClientPlugin.ts JS wrapper around the native RscClientPlugin, similarly bridging the Coordinator into client compilation.
packages/rspack/src/builtin-plugin/rsc/Coordinator.ts JS-side coordinator that shares a binding JsCoordinator instance between server/client compilers and proxies watching behavior from server to client.
packages/rspack/src/builtin-plugin/index.ts Re-exports the rsc helper from the builtin-plugin index.
packages/rspack/src/builtin-loader/swc/types.ts Adds rspackExperiments.reactServerComponents?: boolean to SWC loader options to toggle the RSC SWC transforms.
packages/rspack/src/Watching.ts Moves construction of dependency sets into the process.nextTick path so they reflect any mutations made in compiler.hooks.done, which RSC’s coordinator relies on.
packages/rspack/src/MultiCompiler.ts Minor formatting separation around unsafeFastDrop accessor (no functional change).
packages/rspack/src/Compiler.ts Introduces GET_COMPILER_ID symbol and a non-enumerable property that exposes the underlying JsCompiler ID to the binding-level Coordinator.
packages/rspack/scripts/check-documentation-coverage.ts Excludes the new RSC-related plugins from documentation coverage checks while they stabilize.
packages/rspack/etc/core.api.md Updates the generated public API surface to include rsc, RSC plugin classes, Coordinator, SWC options, and associated types.
crates/swc_plugin_ts_collector/tests/fixture.rs Updates the test harness to pass an Arc<FileName> and SWC comments, matching the new JavaScriptCompiler::transform signature.
crates/rspack_plugin_rsc/src/utils.rs Provides utilities for normalizing module resources, detecting CSS modules, iterating chunk modules, JSON literal encoding, and URI-encoding paths, used by the manifest builder and plugins.
crates/rspack_plugin_rsc/src/server_plugin.rs Implements the Rust-side RscServerPlugin: tracks server component changes, coordinates multi-phase compilations via Coordinator, injects client/SSR/action entries, and wires the RSC manifest runtime module.
crates/rspack_plugin_rsc/src/reference_manifest.rs Declares data structures representing the RSC server reference manifest and module loading metadata (including crossorigin behavior).
crates/rspack_plugin_rsc/src/plugin_state.rs Maintains per-compiler RSC plugin state (client/SSR manifests, entry CSS/JS files, actions, and change tracking) in a global map keyed by CompilerId.
crates/rspack_plugin_rsc/src/manifest_runtime_module.rs Generates the runtime RSC manifest (__webpack_require__.rscM) based on collected plugin state, including server actions, client modules, server-consumer module map, and per-entry assets.
crates/rspack_plugin_rsc/src/loaders/* Adds loaders and corresponding plugins for client entries and action entries; they parse loader query JSON, generate appropriate import/export stubs, and register the loaders via NormalModuleFactoryResolveLoader.
crates/rspack_plugin_rsc/src/lib.rs Exposes the RSC client/server plugins, Coordinator, and loader plugins as the public Rust crate API.
crates/rspack_plugin_rsc/src/hot_reloader.rs Implements hashing-based tracking of changed server components per entry to drive HMR callbacks.
crates/rspack_plugin_rsc/src/coordinator.rs Coordinates the multi-step compilation workflow (server entries → client entries → server actions), with a small state machine and async transitions.
crates/rspack_plugin_rsc/src/constants.rs Centralizes RSC layer names and regexes for CSS and image detection.
crates/rspack_plugin_rsc/src/component_info.rs Walks the module graph from an entry to collect client component imports, CSS imports, actions, and SSR injection flags, driving client/SSR entry injection.
crates/rspack_plugin_rsc/src/client_plugin.rs Implements the Rust-side RscClientPlugin: tracks injected client entries, builds client/SSR manifests (including per-entry JS/CSS assets), and triggers coordinator transitions.
crates/rspack_plugin_rsc/LICENSE Adds an MIT license file for the new RSC plugin crate.
crates/rspack_plugin_rsc/Cargo.toml Declares the new rspack_plugin_rsc crate and its dependencies (SWC, async runtime, simd-json, etc.).
crates/rspack_plugin_javascript/src/parser_plugin/api_plugin.rs Adds support for the __rspack_rsc_manifest__ API symbol, mapping it to the new RuntimeGlobals::RSC_MANIFEST.
crates/rspack_loader_swc/src/rsc_transforms/* Introduces RSC-specific SWC passes: RSC directive handling, server action transforms, server/client entry proxy generation, CJS detection, and RSC metadata collection into RscMeta.
crates/rspack_loader_swc/src/options.rs Wires react_server_components into parsed SWC options, bridging the TS reactServerComponents flag to the Rust side.
crates/rspack_loader_swc/src/lib.rs Enables the RSC SWC passes when the experiment flag is set, passes comments into the JS compiler, and writes back RscMeta, optionally replacing server entry sources with generated proxy modules.
crates/rspack_loader_swc/Cargo.toml Adds RSC transform dependencies (hex, indoc, once_cell, regex, sha2) and makes rspack_util non-optional.
crates/rspack_javascript_compiler/src/compiler/transform.rs Extends JavaScriptCompiler::transform to accept shared comments and uses an Arc<FileName>, propagating comments into JavaScriptTransformer.
crates/rspack_javascript_compiler/examples/transform.rs Updates the example to match the new transform API, including comments and Arc<FileName>.
crates/rspack_core/src/runtime_globals.rs Introduces RuntimeGlobals::RSC_MANIFEST and maps it to __webpack_require__.rscM.
crates/rspack_core/src/module_graph/mod.rs Adds get_resolved_module helper for looking up the resolved module identifier from a dependency ID, simplifying RSC graph traversals.
crates/rspack_core/src/module.rs Adds RscModuleType and RscMeta to BuildInfo for per-module RSC metadata, and implements cacheable serialization for Wtf8Atoms and the action ID map.
crates/rspack_core/src/compiler/rebuild.rs Wraps rebuild with calls to new CompilerDone/CompilerFailed hooks so compiler plugins (including RSC) are notified of rebuild outcomes.
crates/rspack_core/src/compiler/mod.rs Defines CompilerDone/CompilerFailed hooks, adds CompilerId as a cacheable ID type, and wraps build to invoke these hooks on success/failure.
crates/rspack_cacheable/src/with/as_preset/swc.rs Extends the generic SWC AsPreset serializer to support Wtf8Atom, used in RscMeta.
crates/rspack_binding_api/src/swc.rs Updates the binding-side transform wrapper to pass comments and Arc<FileName> into JavaScriptCompiler::transform.
crates/rspack_binding_api/src/raw_options/raw_builtins/mod.rs Adds BuiltinPluginName::RscServerPlugin/RscClientPlugin, wiring them to rspack_plugin_rsc via new JS-exposed options and the JsCoordinator.
crates/rspack_binding_api/src/plugins/rsc.rs Implements the Node binding layer for RSC: JsCoordinator (bridging compiler IDs from JS) and JS-visible RSC plugin options that are converted into Rust options.
crates/rspack_binding_api/src/plugins/mod.rs Re-exports JsCoordinator and the RSC plugin option types for use in the TS side.
crates/rspack_binding_api/src/lib.rs Automatically registers the RSC loader plugins in the default JsCompiler and exposes a get_compiler_id method to JS.
crates/rspack_binding_api/Cargo.toml Adds rspack_plugin_rsc as a dependency so bindings can construct its plugins.
crates/node_binding/scripts/banner.d.ts Extends the banner with a CompilerId type alias and coordinates its exposure in the generated N-API declarations.
crates/node_binding/rspack.wasi.cjs / rspack.wasi-browser.js Re-exports the new JsCoordinator constructor from the WASI bindings.
crates/node_binding/napi-binding.d.ts Updates the N-API TypeScript declarations with CompilerId, the JsCoordinator class, RSC builtin plugin names, plugin option types, and JsCompiler.getCompilerId.
Cargo.toml / Cargo.lock Wires the rspack_plugin_rsc crate into the workspace and adds shared dependencies (e.g. form_urlencoded) to the root manifest.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@hardfist hardfist merged commit 8edf54a into main Jan 23, 2026
78 of 83 checks passed
@hardfist hardfist deleted the react-server-component branch January 23, 2026 09:07
let module = &loader_context.context.module;
let is_react_server_layer = module
.get_layer()
.is_some_and(|layer| layer == "react-server-components");
Copy link

Choose a reason for hiding this comment

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

@copilot There might be a better approach to avoid hard coding the same string in multiple Rust crates.

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

Labels

release: feature release: feature related release(mr only) team The issue/pr is created by the member of Rspack.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants