main
js 115 lines 3.54 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @flow
8 */
9
10 /**
11 * This is a renderer of React that doesn't have a render target output.
12 * It is useful to demonstrate the internals of the reconciler in isolation
13 * and for testing semantics of reconciliation separate from the host
14 * environment.
15 */
16
17 import type {ReactClientValue} from 'react-server/src/ReactFlightServer';
18
19 import {saveModule} from 'react-noop-renderer/flight-modules';
20
21 import ReactFlightServer from 'react-server/flight';
22
23 type Destination = Array<Uint8Array | string>;
24
25 const textEncoder = new TextEncoder();
26
27 // $FlowFixMe[prop-missing]
28 // $FlowFixMe[incompatible-type]
29 const ReactNoopFlightServer = ReactFlightServer({
30 scheduleMicrotask(callback: () => void) {
31 callback();
32 },
33 scheduleWork(callback: () => void) {
34 callback();
35 },
36 beginWriting(destination: Destination): void {},
37 writeChunk(destination: Destination, chunk: string): void {
38 destination.push(chunk);
39 },
40 writeChunkAndReturn(destination: Destination, chunk: string): boolean {
41 destination.push(chunk);
42 return true;
43 },
44 completeWriting(destination: Destination): void {},
45 close(destination: Destination): void {},
46 closeWithError(destination: Destination, error: mixed): void {},
47 flushBuffered(destination: Destination): void {},
48 stringToChunk(content: string): Uint8Array {
49 return textEncoder.encode(content);
50 },
51 stringToPrecomputedChunk(content: string): Uint8Array {
52 return textEncoder.encode(content);
53 },
54 isClientReference(reference: Object): boolean {
55 return reference.$$typeof === Symbol.for('react.client.reference');
56 },
57 isServerReference(reference: Object): boolean {
58 return reference.$$typeof === Symbol.for('react.server.reference');
59 },
60 getClientReferenceKey(reference: Object): Object {
61 return reference;
62 },
63 resolveClientReferenceMetadata(
64 config: void,
65 reference: {$$typeof: symbol, value: any},
66 ) {
67 return saveModule(reference.value);
68 },
69 });
70
71 type Options = {
72 environmentName?: string | (() => string),
73 filterStackFrame?: (url: string, functionName: string) => boolean,
74 identifierPrefix?: string,
75 signal?: AbortSignal,
76 debugChannel?: {onMessage?: (message: string) => void},
77 onError?: (error: mixed) => void,
78 startTime?: number,
79 };
80
81 function render(model: ReactClientValue, options?: Options): Destination {
82 const destination: Destination = [];
83 const bundlerConfig = undefined;
84 const request = ReactNoopFlightServer.createRequest(
85 model,
86 // $FlowFixMe[incompatible-type]
87 bundlerConfig,
88 options ? options.onError : undefined,
89 options ? options.identifierPrefix : undefined,
90 undefined,
91 options ? options.startTime : undefined,
92 __DEV__ && options ? options.environmentName : undefined,
93 __DEV__ && options ? options.filterStackFrame : undefined,
94 // $FlowFixMe[incompatible-type]
95 __DEV__ && options && options.debugChannel !== undefined,
96 );
97 const signal = options ? options.signal : undefined;
98 if (signal) {
99 ReactNoopFlightServer.attachAbortSignal(request, signal);
100 }
101 if (__DEV__ && options && options.debugChannel !== undefined) {
102 options.debugChannel.onMessage = message => {
103 ReactNoopFlightServer.resolveDebugMessage(request, message);
104 };
105 }
106 ReactNoopFlightServer.startWork(request);
107 ReactNoopFlightServer.startFlowing(
108 request,
109 // $FlowFixMe[incompatible-type]
110 destination,
111 );
112 return destination;
113 }
114
115 export {render};