3
3
// `--condition react-server`. If we did try to do that the main process
4
4
// couldn't do SSR because it would be missing client-side React functions
5
5
// like `useState` and `createContext`.
6
- import type { Buffer } from 'node:buffer'
6
+ import { Buffer } from 'node:buffer'
7
7
import path from 'node:path'
8
- import { Writable } from 'node:stream'
9
8
import { parentPort } from 'node:worker_threads'
10
9
11
10
import { createElement } from 'react'
12
11
13
- import RSDWServer from 'react-server-dom-webpack/server'
12
+ import { renderToReadableStream } from 'react-server-dom-webpack/server.edge '
14
13
15
14
import { getPaths } from '@redwoodjs/project-config'
16
15
import {
@@ -28,16 +27,9 @@ import type {
28
27
RenderInput ,
29
28
} from './rscWorkerCommunication.js'
30
29
31
- // TODO (RSC): We should look into importing renderToReadableStream from
32
- // 'react-server-dom-webpack/server.browser' so that we can respond with web
33
- // streams
34
- const { renderToPipeableStream } = RSDWServer
35
-
36
30
let absoluteClientEntries : Record < string , string > = { }
37
31
const serverStorage = createServerStorage ( )
38
32
39
- type PipeableStream = { pipe < T extends Writable > ( destination : T ) : T }
40
-
41
33
const handleSetClientEntries = async ( {
42
34
id,
43
35
} : MessageReq & { type : 'setClientEntries' } ) => {
@@ -73,21 +65,17 @@ const handleRender = async ({ id, input }: MessageReq & { type: 'render' }) => {
73
65
serverStorage . run ( reqMap , async ( ) => {
74
66
try {
75
67
// @MARK run render with map initialised
76
- const pipeable = input . rscId
68
+ const readable = input . rscId
77
69
? await renderRsc ( input )
78
70
: await handleRsa ( input )
79
71
80
- const writable = new Writable ( {
81
- write ( chunk , encoding , callback ) {
82
- if ( encoding !== ( 'buffer' as any ) ) {
83
- throw new Error ( 'Unknown encoding' )
84
- }
85
-
72
+ const writable = new WritableStream ( {
73
+ write ( chunk ) {
86
74
if ( ! parentPort ) {
87
75
throw new Error ( 'parentPort is undefined' )
88
76
}
89
77
90
- const buffer : Buffer = chunk
78
+ const buffer = Buffer . from ( chunk )
91
79
const message : MessageRes = {
92
80
id,
93
81
type : 'buf' ,
@@ -96,20 +84,18 @@ const handleRender = async ({ id, input }: MessageReq & { type: 'render' }) => {
96
84
len : buffer . length ,
97
85
}
98
86
parentPort . postMessage ( message , [ message . buf ] )
99
- callback ( )
100
87
} ,
101
- final ( callback ) {
88
+ close ( ) {
102
89
if ( ! parentPort ) {
103
90
throw new Error ( 'parentPort is undefined' )
104
91
}
105
92
106
93
const message : MessageRes = { id, type : 'end' }
107
94
parentPort . postMessage ( message )
108
- callback ( )
109
95
} ,
110
96
} )
111
97
112
- pipeable . pipe ( writable )
98
+ readable . pipeTo ( writable )
113
99
} catch ( err ) {
114
100
if ( ! parentPort ) {
115
101
throw new Error ( 'parentPort is undefined' )
@@ -223,7 +209,7 @@ function getBundlerConfig() {
223
209
return bundlerConfig
224
210
}
225
211
226
- async function renderRsc ( input : RenderInput ) : Promise < PipeableStream > {
212
+ async function renderRsc ( input : RenderInput ) : Promise < ReadableStream > {
227
213
if ( input . rsaId || ! input . args ) {
228
214
throw new Error (
229
215
"Unexpected input. Can't request both RSCs and execute RSAs at the same time." ,
@@ -237,12 +223,13 @@ async function renderRsc(input: RenderInput): Promise<PipeableStream> {
237
223
console . log ( 'renderRsc input' , input )
238
224
239
225
const serverRoutes = await getRoutesComponent ( )
240
- const element = createElement ( serverRoutes , input . props )
226
+ // TODO (RSC): Should this have the same shape as for handleRsa?
227
+ const model = createElement ( serverRoutes , input . props )
241
228
242
229
console . log ( 'rscWorker.ts renderRsc renderRsc props' , input . props )
243
- console . log ( 'rscWorker.ts renderRsc element ' , element )
230
+ console . log ( 'rscWorker.ts renderRsc model ' , model )
244
231
245
- return renderToPipeableStream ( element , getBundlerConfig ( ) )
232
+ return renderToReadableStream ( model , getBundlerConfig ( ) )
246
233
// TODO (RSC): We used to transform() the stream here to remove
247
234
// "prefixToRemove", which was the common base path to all filenames. We
248
235
// then added it back in handleRsa with a simple
@@ -260,7 +247,7 @@ function isSerializedFormData(data?: unknown): data is SerializedFormData {
260
247
return ! ! data && ( data as SerializedFormData ) ?. __formData__
261
248
}
262
249
263
- async function handleRsa ( input : RenderInput ) : Promise < PipeableStream > {
250
+ async function handleRsa ( input : RenderInput ) : Promise < ReadableStream > {
264
251
console . log ( 'handleRsa input' , input )
265
252
266
253
if ( ! input . rsaId || ! input . args ) {
@@ -296,13 +283,13 @@ async function handleRsa(input: RenderInput): Promise<PipeableStream> {
296
283
297
284
const serverRoutes = await getRoutesComponent ( )
298
285
console . log ( 'rscWorker.ts handleRsa serverRoutes' , serverRoutes )
299
- const elements = {
286
+ const model = {
300
287
Routes : createElement ( serverRoutes , {
301
288
location : { pathname : '/' , search : '' } ,
302
289
} ) ,
303
290
__rwjs__rsa_data : data ,
304
291
}
305
- console . log ( 'rscWorker.ts handleRsa elements ' , elements )
292
+ console . log ( 'rscWorker.ts handleRsa model ' , model )
306
293
307
- return renderToPipeableStream ( elements , getBundlerConfig ( ) )
294
+ return renderToReadableStream ( model , getBundlerConfig ( ) )
308
295
}
0 commit comments