Skip to content

Commit 68b7bdb

Browse files
committed
Parcel too
1 parent c80e31f commit 68b7bdb

File tree

6 files changed

+216
-7
lines changed

6 files changed

+216
-7
lines changed

packages/react-server-dom-parcel/npm/server.node.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ if (process.env.NODE_ENV === 'production') {
77
s = require('./cjs/react-server-dom-parcel-server.node.development.js');
88
}
99

10+
exports.renderToReadableStream = s.renderToReadableStream;
1011
exports.renderToPipeableStream = s.renderToPipeableStream;
11-
exports.decodeReplyFromBusboy = s.decodeReplyFromBusboy;
1212
exports.decodeReply = s.decodeReply;
13+
exports.decodeReplyFromBusboy = s.decodeReplyFromBusboy;
14+
exports.decodeReplyFromAsyncIterable = s.decodeReplyFromAsyncIterable;
1315
exports.decodeAction = s.decodeAction;
1416
exports.decodeFormState = s.decodeFormState;
1517
exports.createClientReference = s.createClientReference;

packages/react-server-dom-parcel/npm/static.node.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ if (process.env.NODE_ENV === 'production') {
77
s = require('./cjs/react-server-dom-parcel-server.node.development.js');
88
}
99

10+
if (s.unstable_prerender) {
11+
exports.unstable_prerender = s.unstable_prerender;
12+
}
1013
if (s.unstable_prerenderToNodeStream) {
1114
exports.unstable_prerenderToNodeStream = s.unstable_prerenderToNodeStream;
1215
}

packages/react-server-dom-parcel/server.node.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99

1010
export {
1111
renderToPipeableStream,
12-
decodeReplyFromBusboy,
12+
renderToReadableStream,
1313
decodeReply,
14+
decodeReplyFromBusboy,
15+
decodeReplyFromAsyncIterable,
1416
decodeAction,
1517
decodeFormState,
1618
createClientReference,

packages/react-server-dom-parcel/src/server/ReactFlightDOMServerNode.js

Lines changed: 199 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ import type {
2121
} from '../client/ReactFlightClientConfigBundlerParcel';
2222

2323
import {Readable} from 'stream';
24+
25+
import {ASYNC_ITERATOR} from 'shared/ReactSymbols';
26+
2427
import {
2528
createRequest,
2629
createPrerenderRequest,
@@ -35,6 +38,7 @@ import {
3538
reportGlobalError,
3639
close,
3740
resolveField,
41+
resolveFile,
3842
resolveFileInfo,
3943
resolveFileChunk,
4044
resolveFileComplete,
@@ -56,9 +60,12 @@ export {
5660
registerServerReference,
5761
} from '../ReactFlightParcelReferences';
5862

63+
import {textEncoder} from 'react-server/src/ReactServerStreamConfigNode';
64+
5965
import type {TemporaryReferenceSet} from 'react-server/src/ReactFlightServerTemporaryReferences';
6066

6167
export {createTemporaryReferenceSet} from 'react-server/src/ReactFlightServerTemporaryReferences';
68+
6269
export type {TemporaryReferenceSet};
6370

6471
function createDrainHandler(destination: Destination, request: Request) {
@@ -88,6 +95,7 @@ type PipeableStream = {
8895

8996
export function renderToPipeableStream(
9097
model: ReactClientValue,
98+
9199
options?: Options,
92100
): PipeableStream {
93101
const request = createRequest(
@@ -131,11 +139,91 @@ export function renderToPipeableStream(
131139
};
132140
}
133141

134-
function createFakeWritable(readable: any): Writable {
142+
function createFakeWritableFromReadableStreamController(
143+
controller: ReadableStreamController,
144+
): Writable {
145+
// The current host config expects a Writable so we create
146+
// a fake writable for now to push into the Readable.
147+
return ({
148+
write(chunk: string | Uint8Array) {
149+
if (typeof chunk === 'string') {
150+
chunk = textEncoder.encode(chunk);
151+
}
152+
controller.enqueue(chunk);
153+
// in web streams there is no backpressure so we can alwas write more
154+
return true;
155+
},
156+
end() {
157+
controller.close();
158+
},
159+
destroy(error) {
160+
// $FlowFixMe[method-unbinding]
161+
if (typeof controller.error === 'function') {
162+
// $FlowFixMe[incompatible-call]: This is an Error object or the destination accepts other types.
163+
controller.error(error);
164+
} else {
165+
controller.close();
166+
}
167+
},
168+
}: any);
169+
}
170+
171+
export function renderToReadableStream(
172+
model: ReactClientValue,
173+
174+
options?: Options & {
175+
signal?: AbortSignal,
176+
},
177+
): ReadableStream {
178+
const request = createRequest(
179+
model,
180+
null,
181+
options ? options.onError : undefined,
182+
options ? options.identifierPrefix : undefined,
183+
options ? options.onPostpone : undefined,
184+
options ? options.temporaryReferences : undefined,
185+
__DEV__ && options ? options.environmentName : undefined,
186+
__DEV__ && options ? options.filterStackFrame : undefined,
187+
);
188+
if (options && options.signal) {
189+
const signal = options.signal;
190+
if (signal.aborted) {
191+
abort(request, (signal: any).reason);
192+
} else {
193+
const listener = () => {
194+
abort(request, (signal: any).reason);
195+
signal.removeEventListener('abort', listener);
196+
};
197+
signal.addEventListener('abort', listener);
198+
}
199+
}
200+
let writable: Writable;
201+
const stream = new ReadableStream(
202+
{
203+
type: 'bytes',
204+
start: (controller): ?Promise<void> => {
205+
writable = createFakeWritableFromReadableStreamController(controller);
206+
startWork(request);
207+
},
208+
pull: (controller): ?Promise<void> => {
209+
startFlowing(request, writable);
210+
},
211+
cancel: (reason): ?Promise<void> => {
212+
stopFlowing(request);
213+
abort(request, reason);
214+
},
215+
},
216+
// $FlowFixMe[prop-missing] size() methods are not allowed on byte streams.
217+
{highWaterMark: 0},
218+
);
219+
return stream;
220+
}
221+
222+
function createFakeWritableFromNodeReadable(readable: any): Writable {
135223
// The current host config expects a Writable so we create
136224
// a fake writable for now to push into the Readable.
137225
return ({
138-
write(chunk) {
226+
write(chunk: string | Uint8Array) {
139227
return readable.push(chunk);
140228
},
141229
end() {
@@ -163,6 +251,7 @@ type StaticResult = {
163251

164252
export function prerenderToNodeStream(
165253
model: ReactClientValue,
254+
166255
options?: PrerenderOptions,
167256
): Promise<StaticResult> {
168257
return new Promise((resolve, reject) => {
@@ -173,7 +262,7 @@ export function prerenderToNodeStream(
173262
startFlowing(request, writable);
174263
},
175264
});
176-
const writable = createFakeWritable(readable);
265+
const writable = createFakeWritableFromNodeReadable(readable);
177266
resolve({prelude: readable});
178267
}
179268

@@ -207,6 +296,69 @@ export function prerenderToNodeStream(
207296
});
208297
}
209298

299+
export function prerender(
300+
model: ReactClientValue,
301+
302+
options?: Options & {
303+
signal?: AbortSignal,
304+
},
305+
): Promise<{
306+
prelude: ReadableStream,
307+
}> {
308+
return new Promise((resolve, reject) => {
309+
const onFatalError = reject;
310+
function onAllReady() {
311+
let writable: Writable;
312+
const stream = new ReadableStream(
313+
{
314+
type: 'bytes',
315+
start: (controller): ?Promise<void> => {
316+
writable =
317+
createFakeWritableFromReadableStreamController(controller);
318+
},
319+
pull: (controller): ?Promise<void> => {
320+
startFlowing(request, writable);
321+
},
322+
cancel: (reason): ?Promise<void> => {
323+
stopFlowing(request);
324+
abort(request, reason);
325+
},
326+
},
327+
// $FlowFixMe[prop-missing] size() methods are not allowed on byte streams.
328+
{highWaterMark: 0},
329+
);
330+
resolve({prelude: stream});
331+
}
332+
const request = createPrerenderRequest(
333+
model,
334+
null,
335+
onAllReady,
336+
onFatalError,
337+
options ? options.onError : undefined,
338+
options ? options.identifierPrefix : undefined,
339+
options ? options.onPostpone : undefined,
340+
options ? options.temporaryReferences : undefined,
341+
__DEV__ && options ? options.environmentName : undefined,
342+
__DEV__ && options ? options.filterStackFrame : undefined,
343+
);
344+
if (options && options.signal) {
345+
const signal = options.signal;
346+
if (signal.aborted) {
347+
const reason = (signal: any).reason;
348+
abort(request, reason);
349+
} else {
350+
const listener = () => {
351+
const reason = (signal: any).reason;
352+
abort(request, reason);
353+
signal.removeEventListener('abort', listener);
354+
};
355+
signal.addEventListener('abort', listener);
356+
}
357+
}
358+
startWork(request);
359+
});
360+
}
361+
210362
let serverManifest = {};
211363
export function registerServerActions(manifest: ServerManifest) {
212364
// This function is called by the bundler to register the manifest.
@@ -292,6 +444,50 @@ export function decodeReply<T>(
292444
return root;
293445
}
294446

447+
export function decodeReplyFromAsyncIterable<T>(
448+
iterable: AsyncIterable<[string, string | File]>,
449+
options?: {temporaryReferences?: TemporaryReferenceSet},
450+
): Thenable<T> {
451+
const iterator: AsyncIterator<[string, string | File]> =
452+
iterable[ASYNC_ITERATOR]();
453+
454+
const response = createResponse(
455+
serverManifest,
456+
'',
457+
options ? options.temporaryReferences : undefined,
458+
);
459+
460+
function progress(
461+
entry:
462+
| {done: false, +value: [string, string | File], ...}
463+
| {done: true, +value: void, ...},
464+
) {
465+
if (entry.done) {
466+
close(response);
467+
} else {
468+
const [name, value] = entry.value;
469+
if (typeof value === 'string') {
470+
resolveField(response, name, value);
471+
} else {
472+
resolveFile(response, name, value);
473+
}
474+
iterator.next().then(progress, error);
475+
}
476+
}
477+
function error(reason: Error) {
478+
reportGlobalError(response, reason);
479+
if (typeof (iterator: any).throw === 'function') {
480+
// The iterator protocol doesn't necessarily include this but a generator do.
481+
// $FlowFixMe should be able to pass mixed
482+
iterator.throw(reason).then(error, error);
483+
}
484+
}
485+
486+
iterator.next().then(progress, error);
487+
488+
return getRoot(response);
489+
}
490+
295491
export function decodeAction<T>(body: FormData): Promise<() => T> | null {
296492
return decodeActionImpl(body, serverManifest);
297493
}

packages/react-server-dom-parcel/src/server/react-flight-dom-server.node.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@
88
*/
99

1010
export {
11+
renderToReadableStream,
1112
renderToPipeableStream,
13+
prerender as unstable_prerender,
1214
prerenderToNodeStream as unstable_prerenderToNodeStream,
13-
decodeReplyFromBusboy,
1415
decodeReply,
16+
decodeReplyFromBusboy,
17+
decodeReplyFromAsyncIterable,
1518
decodeAction,
1619
decodeFormState,
1720
createClientReference,

packages/react-server-dom-parcel/static.node.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,7 @@
77
* @flow
88
*/
99

10-
export {unstable_prerenderToNodeStream} from './src/server/react-flight-dom-server.node';
10+
export {
11+
unstable_prerender,
12+
unstable_prerenderToNodeStream,
13+
} from './src/server/react-flight-dom-server.node';

0 commit comments

Comments
 (0)