|
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