|
1 |
| -// import * as React from 'react'; |
2 |
| -// import { createFromNodeStream } from 'react-on-rails-rsc/client.node'; |
3 |
| -// import transformRSCStream from './transformRSCNodeStreamAndReplayConsoleLogs'; |
4 |
| -// import loadJsonFile from './loadJsonFile'; |
5 |
| - |
6 |
| -// if (!('use' in React && typeof React.use === 'function')) { |
7 |
| -// throw new Error('React.use is not defined. Please ensure you are using React 18 with experimental features enabled or React 19+ to use server components.'); |
8 |
| -// } |
9 |
| - |
10 |
| -// const { use } = React; |
11 |
| - |
12 |
| -// export type RSCServerRootProps = { |
13 |
| -// getRscPromise: NodeJS.ReadableStream, |
14 |
| -// reactClientManifestFileName: string, |
15 |
| -// reactServerManifestFileName: string, |
16 |
| -// } |
17 |
| - |
18 |
| -// const createFromFetch = (stream: NodeJS.ReadableStream, ssrManifest: Record<string, unknown>) => { |
19 |
| -// const transformedStream = transformRSCStream(stream); |
20 |
| -// return createFromNodeStream(transformedStream, ssrManifest); |
21 |
| -// } |
22 |
| - |
23 |
| -// const createSSRManifest = (reactServerManifestFileName: string, reactClientManifestFileName: string) => { |
24 |
| -// const reactServerManifest = loadJsonFile(reactServerManifestFileName); |
25 |
| -// const reactClientManifest = loadJsonFile(reactClientManifestFileName); |
26 |
| - |
27 |
| -// const ssrManifest = { |
28 |
| -// moduleLoading: { |
29 |
| -// prefix: "/webpack/development/", |
30 |
| -// crossOrigin: null, |
31 |
| -// }, |
32 |
| -// moduleMap: {} as Record<string, unknown>, |
33 |
| -// }; |
34 |
| - |
35 |
| -// Object.entries(reactClientManifest).forEach(([aboluteFileUrl, clientFileBundlingInfo]) => { |
36 |
| -// const serverFileBundlingInfo = reactServerManifest[aboluteFileUrl]; |
37 |
| -// ssrManifest.moduleMap[(clientFileBundlingInfo as { id: string }).id] = { |
38 |
| -// '*': { |
39 |
| -// id: (serverFileBundlingInfo as { id: string }).id, |
40 |
| -// chunks: (serverFileBundlingInfo as { chunks: string[] }).chunks, |
41 |
| -// name: '*', |
42 |
| -// } |
43 |
| -// }; |
44 |
| -// }); |
45 |
| - |
46 |
| -// return ssrManifest; |
47 |
| -// } |
48 |
| - |
49 |
| -// const RSCServerRoot = ({ |
50 |
| -// getRscPromise, |
51 |
| -// reactClientManifestFileName, |
52 |
| -// reactServerManifestFileName, |
53 |
| -// }: RSCServerRootProps) => { |
54 |
| -// const ssrManifest = createSSRManifest(reactServerManifestFileName, reactClientManifestFileName); |
55 |
| -// return use(createFromFetch(getRscPromise, ssrManifest)); |
56 |
| -// }; |
57 |
| - |
58 |
| -// export default RSCServerRoot; |
| 1 | +import * as React from 'react'; |
| 2 | +import { createFromNodeStream } from 'react-on-rails-rsc/client.node'; |
| 3 | +import type { RenderFunction, RailsContext } from './types'; |
| 4 | +import transformRSCStream from './transformRSCNodeStreamAndReplayConsoleLogs'; |
| 5 | +import loadJsonFile from './loadJsonFile'; |
| 6 | + |
| 7 | +declare global { |
| 8 | + function generateRSCPayload( |
| 9 | + componentName: string, |
| 10 | + props: Record<string, unknown>, |
| 11 | + serverSideRSCPayloadParameters: unknown, |
| 12 | + ): Promise<NodeJS.ReadableStream>; |
| 13 | +} |
| 14 | + |
| 15 | +type RSCServerRootProps = { |
| 16 | + componentName: string; |
| 17 | + componentProps: Record<string, unknown>; |
| 18 | +} |
| 19 | + |
| 20 | +if (!('use' in React && typeof React.use === 'function')) { |
| 21 | + throw new Error('React.use is not defined. Please ensure you are using React 18 with experimental features enabled or React 19+ to use server components.'); |
| 22 | +} |
| 23 | + |
| 24 | +const { use } = React; |
| 25 | + |
| 26 | +const createFromReactOnRailsNodeStream = (stream: NodeJS.ReadableStream, ssrManifest: Record<string, unknown>) => { |
| 27 | + const transformedStream = transformRSCStream(stream); |
| 28 | + return createFromNodeStream(transformedStream, ssrManifest); |
| 29 | +} |
| 30 | + |
| 31 | +const createSSRManifest = async (reactServerManifestFileName: string, reactClientManifestFileName: string) => { |
| 32 | + const [reactServerManifest, reactClientManifest] = await Promise.all([ |
| 33 | + loadJsonFile(reactServerManifestFileName), |
| 34 | + loadJsonFile(reactClientManifestFileName), |
| 35 | + ]); |
| 36 | + |
| 37 | + const ssrManifest = { |
| 38 | + moduleLoading: { |
| 39 | + prefix: "/webpack/development/", |
| 40 | + crossOrigin: null, |
| 41 | + }, |
| 42 | + moduleMap: {} as Record<string, unknown>, |
| 43 | + }; |
| 44 | + |
| 45 | + Object.entries(reactClientManifest).forEach(([aboluteFileUrl, clientFileBundlingInfo]) => { |
| 46 | + const serverFileBundlingInfo = reactServerManifest[aboluteFileUrl]; |
| 47 | + ssrManifest.moduleMap[(clientFileBundlingInfo as { id: string }).id] = { |
| 48 | + '*': { |
| 49 | + id: (serverFileBundlingInfo as { id: string }).id, |
| 50 | + chunks: (serverFileBundlingInfo as { chunks: string[] }).chunks, |
| 51 | + name: '*', |
| 52 | + } |
| 53 | + }; |
| 54 | + }); |
| 55 | + |
| 56 | + return ssrManifest; |
| 57 | +} |
| 58 | + |
| 59 | +const RSCServerRoot: RenderFunction = async ({ componentName, componentProps }: RSCServerRootProps, railsContext?: RailsContext) => { |
| 60 | + if (!railsContext?.serverSide || !railsContext?.reactClientManifestFileName || !railsContext?.reactServerClientManifestFileName) { |
| 61 | + throw new Error( |
| 62 | + `${'serverClientManifestFileName and reactServerClientManifestFileName are required. ' + |
| 63 | + 'Please ensure that React Server Component webpack configurations are properly set ' + |
| 64 | + 'as stated in the React Server Component tutorial. The received rails context is: '}${ JSON.stringify(railsContext)}` |
| 65 | + ); |
| 66 | + } |
| 67 | + |
| 68 | + if (typeof generateRSCPayload !== 'function') { |
| 69 | + throw new Error( |
| 70 | + 'generateRSCPayload is not defined. Please ensure that you are using at least version 4.0.0 of ' + |
| 71 | + 'React on Rails Pro and the node renderer, and that ReactOnRailsPro.configuration.enable_rsc_support ' + |
| 72 | + 'is set to true.' |
| 73 | + ); |
| 74 | + } |
| 75 | + |
| 76 | + const ssrManifest = await createSSRManifest( |
| 77 | + railsContext.reactServerClientManifestFileName, |
| 78 | + railsContext.reactClientManifestFileName |
| 79 | + ); |
| 80 | + const rscPayloadStream = await generateRSCPayload( |
| 81 | + componentName, |
| 82 | + componentProps, |
| 83 | + railsContext.serverSideRSCPayloadParameters |
| 84 | + ); |
| 85 | + const serverComponentElement = createFromReactOnRailsNodeStream(rscPayloadStream, ssrManifest); |
| 86 | + |
| 87 | + return () => use(serverComponentElement); |
| 88 | +}; |
| 89 | + |
| 90 | +export default RSCServerRoot; |
0 commit comments