Add support for SSR when the server bundle is webpack bundled v19.1.0 #33540
+21
−69
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
React Server Components SSR with Webpack
Overview
This PR implements support for SSR of React Server Components (RSC) with Webpack bundling. The implementation focuses on properly handling client components in both server and client bundles, ensuring correct rendering and hydration while maintaining the benefits of RSC architecture.
Problem Statement
The current React Server Components implementation assumes direct access to original JS files on the server, which doesn't work well with Webpack-bundled applications. This creates issues when trying to render client components on the server side.
Technical Solution
Client Component Handling
When building the RSC bundle, React removes all client components and replaces them with client references. For example, a client component:
is replaced with:
When the RSC bundle is used to generate the RSC payload, it renders the server
components as their code already exists in it, but it will leave a reference to
the client component in the places where the client component is used.
Client-Side Implementation
1. Client Bundle Building
"use client"
directive as entry points2. Manifest Generation
The RSC plugin generates a
react-client-manifest.json
file mapping client components to their webpack IDs:3. RSC Payload Generation
4. Client-Side Rendering
Server-Side Implementation
1. Current React Behavior
React assumes server has access to original JS files, generating
react-ssr-manifest.json
:So, when React runtime faces the following RSC payload chunk:
It will look at the
react-ssr-manifest.json
file to find the original file path of the client component (in this case, it'sfile:///home/user/my-app/src/app/components/Counter.jsx
). Then, it will load that file and get the client component code from it.As we said before, the info generated by the RSC plugin is only valuable when the server is not using a webpack bundled bundle. However, React runtime supports SSR from webpack bundles. The problem is that the needed info is not provided by the webpack bundle.
2. Proposed Solution
We need a JSON file mapping client module IDs to server module IDs:
The previous example maps the client module ID
779
to the server module ID877
that contains the same client component code (in this case, it'sfile:/// home/user/my-app/src/app/components/Counter.jsx
).Implementation Steps
Development Setup
To implement these changes, we need to modify the
react-server-dom-webpack
package. Here's how we set up our development environment:Fork and clone the React repository from our fork
Make the necessary changes to the
react-server-dom-webpack
package as outlined in this PRBuild the package using the React build system
Copy the built package to
./react-server-dom-webpack
in ourreact-on-rails-rsc
projectRSC Plugin Configuration
isServer
option to differentiate bundlesreact-ssr-manifest.json
generationManifest Generation
react-client-manifest.json
react-server-client-manifest.json
API Changes
buildClientRenderer
instead ofcreateFromNodeStream
buildServerRenderer
instead ofrenderToPipeableStream
API Usage
Design Decisions
Manifest Merging
API Design
buildClientRenderer
/buildServerRenderer
over direct exports