Skip to content

Commit b0f0945

Browse files
refactor: update react-on-rails-rsc dependency to use SSR support and streamline imports for server components
1 parent 8c0afc9 commit b0f0945

File tree

5 files changed

+39
-68
lines changed

5 files changed

+39
-68
lines changed

node_package/src/ReactOnRailsRSC.ts

+13-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { renderToPipeableStream } from 'react-on-rails-rsc/server.node';
1+
import { BundleManifest } from 'react-on-rails-rsc';
2+
import { buildServerRenderer } from 'react-on-rails-rsc/server.node';
23
import { PassThrough, Readable } from 'stream';
34

45
import {
@@ -26,6 +27,8 @@ const stringToStream = (str: string) => {
2627
return stream;
2728
};
2829

30+
let serverRenderer: ReturnType<typeof buildServerRenderer> | undefined;
31+
2932
const streamRenderRSCComponent = (
3033
reactRenderingResult: StreamableComponentResult,
3134
options: RSCRenderParams,
@@ -44,9 +47,15 @@ const streamRenderRSCComponent = (
4447

4548
const { pipeToTransform, readableStream, emitError } =
4649
transformRenderStreamChunksToResultObject(renderState);
47-
Promise.all([loadJsonFile(reactClientManifestFileName), reactRenderingResult])
48-
.then(([reactClientManifest, reactElement]) => {
49-
const rscStream = renderToPipeableStream(reactElement, reactClientManifest, {
50+
Promise.resolve(reactRenderingResult)
51+
.then(async (reactElement) => {
52+
if (!serverRenderer) {
53+
const reactClientManifest = await loadJsonFile<BundleManifest>(reactClientManifestFileName);
54+
serverRenderer = buildServerRenderer(reactClientManifest);
55+
}
56+
57+
const { renderToPipeableStream } = serverRenderer;
58+
const rscStream = renderToPipeableStream(reactElement, {
5059
onError: (err) => {
5160
const error = convertToError(err);
5261
console.error('Error in RSC stream', error);

node_package/src/getReactServerComponent.client.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from 'react';
2-
import { createFromReadableStream } from 'react-on-rails-rsc/client';
2+
import { createFromReadableStream } from 'react-on-rails-rsc/client.browser';
33
import { fetch } from './utils.ts';
44
import transformRSCStreamAndReplayConsoleLogs from './transformRSCStreamAndReplayConsoleLogs.ts';
55
import { RailsContext } from './types/index.ts';
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { createFromNodeStream } from 'react-on-rails-rsc/client.node';
1+
import { BundleManifest } from 'react-on-rails-rsc';
2+
import { buildClientRenderer } from 'react-on-rails-rsc/client.node';
23
import transformRSCStream from './transformRSCNodeStream.ts';
34
import loadJsonFile from './loadJsonFile.ts';
45
import { RailsContext } from './types/index.ts';
@@ -9,63 +10,24 @@ type RSCServerRootProps = {
910
railsContext: RailsContext;
1011
};
1112

12-
const createFromReactOnRailsNodeStream = (
13-
stream: NodeJS.ReadableStream,
14-
ssrManifest: Record<string, unknown>,
15-
) => {
16-
const transformedStream = transformRSCStream(stream);
17-
return createFromNodeStream(transformedStream, ssrManifest);
18-
};
13+
let clientRenderer: ReturnType<typeof buildClientRenderer> | undefined;
1914

20-
/**
21-
* Creates an SSR manifest for React's server components runtime.
22-
*
23-
* This function:
24-
* 1. Loads the server and client component manifests
25-
* 2. Creates a mapping between client and server module IDs
26-
* 3. Builds a moduleMap structure required by React's SSR runtime
27-
*
28-
* The manifest allows React to correctly associate server components
29-
* with their client counterparts during hydration.
30-
*
31-
* @param reactServerManifestFileName - Path to the server manifest file
32-
* @param reactClientManifestFileName - Path to the client manifest file
33-
* @returns A Promise resolving to the SSR manifest object
34-
*/
35-
const createSSRManifest = async (
15+
const createFromReactOnRailsNodeStream = async (
16+
stream: NodeJS.ReadableStream,
3617
reactServerManifestFileName: string,
3718
reactClientManifestFileName: string,
3819
) => {
39-
const [reactServerManifest, reactClientManifest] = await Promise.all([
40-
loadJsonFile<Record<string, { id: string; chunks: string[] }>>(reactServerManifestFileName),
41-
loadJsonFile<Record<string, { id: string }>>(reactClientManifestFileName),
42-
]);
43-
44-
const moduleMap: Record<string, unknown> = {};
45-
Object.entries(reactClientManifest).forEach(([aboluteFileUrl, clientFileBundlingInfo]) => {
46-
const { id, chunks } = reactServerManifest[aboluteFileUrl];
47-
moduleMap[clientFileBundlingInfo.id] = {
48-
'*': {
49-
id,
50-
chunks,
51-
name: '*',
52-
},
53-
};
54-
});
55-
56-
const ssrManifest = {
57-
// The `moduleLoading` property is utilized by the React runtime to load JavaScript modules.
58-
// It can accept options such as `prefix` and `crossOrigin` to specify the path and crossorigin attribute for the modules.
59-
// In our case, since the server code is bundled into a single bundle, there is no need to load additional JavaScript modules.
60-
// As a result, we set this property to an empty object because it will not be used.
61-
moduleLoading: {
62-
prefix: `/webpack/${process.env.NODE_ENV}/`,
63-
crossOrigin: null,
64-
},
65-
moduleMap,
66-
};
20+
if (!clientRenderer) {
21+
const [reactServerManifest, reactClientManifest] = await Promise.all([
22+
loadJsonFile<BundleManifest>(reactServerManifestFileName),
23+
loadJsonFile<BundleManifest>(reactClientManifestFileName),
24+
]);
25+
clientRenderer = buildClientRenderer(reactClientManifest, reactServerManifest);
26+
}
6727

68-
return ssrManifest;
28+
const { createFromNodeStream } = clientRenderer;
29+
const transformedStream = transformRSCStream(stream);
30+
return createFromNodeStream<React.ReactNode>(transformedStream);
6931
};
7032

7133
/**
@@ -115,17 +77,17 @@ const getReactServerComponent = async ({
11577
);
11678
}
11779

118-
const ssrManifest = await createSSRManifest(
119-
railsContext.reactServerClientManifestFileName,
120-
railsContext.reactClientManifestFileName,
121-
);
12280
const rscPayloadStream = await ReactOnRails.getRSCPayloadStream(
12381
componentName,
12482
componentProps,
12583
railsContext,
12684
);
12785

128-
return createFromReactOnRailsNodeStream(rscPayloadStream, ssrManifest);
86+
return createFromReactOnRailsNodeStream(
87+
rscPayloadStream,
88+
railsContext.reactServerClientManifestFileName,
89+
railsContext.reactClientManifestFileName,
90+
);
12991
};
13092

13193
export default getReactServerComponent;

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
"publint": "^0.3.8",
6565
"react": "^19.0.0",
6666
"react-dom": "^19.0.0",
67-
"react-on-rails-rsc": "git+https://github.com/shakacode/react_on_rails_rsc.git#add-support-for-generating-client-components-manifest-for-server-bundle",
67+
"react-on-rails-rsc": "git+https://github.com/shakacode/react_on_rails_rsc.git#ssr-support",
6868
"redux": "^4.2.1",
6969
"ts-jest": "^29.2.5",
7070
"typescript": "^5.8.3",
@@ -73,7 +73,7 @@
7373
"peerDependencies": {
7474
"react": ">= 16",
7575
"react-dom": ">= 16",
76-
"react-on-rails-rsc": "git+https://github.com/shakacode/react_on_rails_rsc.git#add-support-for-generating-client-components-manifest-for-server-bundle"
76+
"react-on-rails-rsc": "git+https://github.com/shakacode/react_on_rails_rsc.git#ssr-support"
7777
},
7878
"files": [
7979
"node_package/lib"

yarn.lock

+3-3
Original file line numberDiff line numberDiff line change
@@ -5215,9 +5215,9 @@ react-is@^18.0.0:
52155215
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
52165216
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
52175217

5218-
"react-on-rails-rsc@git+https://github.com/shakacode/react_on_rails_rsc.git#add-support-for-generating-client-components-manifest-for-server-bundle":
5219-
version "19.0.0-rc.2"
5220-
resolved "git+https://github.com/shakacode/react_on_rails_rsc.git#f49dc3fd94629ff23c1c6a397b19b6feff437b2f"
5218+
"react-on-rails-rsc@git+https://github.com/shakacode/react_on_rails_rsc.git#ssr-support":
5219+
version "19.0.0"
5220+
resolved "git+https://github.com/shakacode/react_on_rails_rsc.git#f71fabc8eb62b08cb4d590da85d2b519d9f8d451"
52215221
dependencies:
52225222
acorn-loose "^8.3.0"
52235223
neo-async "^2.6.1"

0 commit comments

Comments
 (0)