main
js 126 lines 3.55 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 {Thenable} from 'shared/ReactTypes';
18 import type {FindSourceMapURLCallback} from 'react-client/flight';
19
20 import {readModule} from 'react-noop-renderer/flight-modules';
21
22 import ReactFlightClient from 'react-client/flight';
23
24 type Source = Array<Uint8Array>;
25
26 const decoderOptions = {stream: true};
27
28 const {createResponse, createStreamState, processBinaryChunk, getRoot, close} =
29 // $FlowFixMe[prop-missing]
30 // $FlowFixMe[incompatible-type]
31 ReactFlightClient({
32 createStringDecoder() {
33 return new TextDecoder();
34 },
35 readPartialStringChunk(decoder: TextDecoder, buffer: Uint8Array): string {
36 return decoder.decode(buffer, decoderOptions);
37 },
38 readFinalStringChunk(decoder: TextDecoder, buffer: Uint8Array): string {
39 return decoder.decode(buffer);
40 },
41 resolveClientReference(bundlerConfig: null, idx: string) {
42 return idx;
43 },
44 prepareDestinationForModule(moduleLoading: null, metadata: string) {},
45 preloadModule(idx: string) {},
46 requireModule(idx: string) {
47 return readModule(idx);
48 },
49 bindToConsole(methodName, args, badgeName) {
50 // $FlowFixMe[incompatible-type]
51 return Function.prototype.bind.apply(
52 // eslint-disable-next-line react-internal/no-production-logging
53 console[methodName],
54 [console].concat(args),
55 );
56 },
57 checkEvalAvailabilityOnceDev,
58 });
59
60 type ReadOptions = {|
61 findSourceMapURL?: FindSourceMapURLCallback,
62 debugChannel?: {onMessage: (message: string) => void},
63 close?: boolean,
64 |};
65
66 function read<T>(source: Source, options: ReadOptions): Thenable<T> {
67 const response = createResponse(
68 // $FlowFixMe[incompatible-type]
69 source,
70 null,
71 // $FlowFixMe[incompatible-type]
72 null,
73 undefined,
74 undefined,
75 undefined,
76 undefined,
77 false,
78 options !== undefined ? options.findSourceMapURL : undefined,
79 true,
80 undefined,
81 __DEV__ && options !== undefined && options.debugChannel !== undefined
82 ? // $FlowFixMe[incompatible-type]
83 options.debugChannel.onMessage
84 : undefined,
85 );
86 const streamState = createStreamState(response, source);
87 for (let i = 0; i < source.length; i++) {
88 processBinaryChunk(
89 response,
90 streamState,
91 source[i],
92 // $FlowFixMe[extra-arg]
93 0,
94 );
95 }
96 if (options !== undefined && options.close) {
97 close(response);
98 }
99 return getRoot(response);
100 }
101
102 let hasConfirmedEval = false;
103 function checkEvalAvailabilityOnceDev(): void {
104 if (__DEV__) {
105 if (!hasConfirmedEval) {
106 hasConfirmedEval = true;
107 try {
108 // eslint-disable-next-line no-eval
109 (0, eval)('null');
110 } catch {
111 console.error(
112 'eval() is not supported in this environment. ' +
113 'React requires eval() in development mode for various debugging features ' +
114 'like reconstructing callstacks from a different environment.\n' +
115 'React will never use eval() in production mode',
116 );
117 }
118 }
119 } else {
120 throw new Error(
121 'checkEvalAvailabilityOnceDev should never be called in production mode. This is a bug in React.',
122 );
123 }
124 }
125
126 export {read};