@samitouri / QOS-React-1 / commits / 5e4279134d

[noop] Typecheck `react-noop-renderer` against host config and renderer API (#35944)

Sebastian "Sebbie" Silbermann committed Mar 4, 2026 at 13:52 UTC 5e4279134dbc29116407a5ec515e74e2c0ae5018
21 files changed +782 -65
packages/react-client/flight.js
+7
@@ -7,4 +7,11 @@
7 * @flow
8 */
9
10 +import typeof * as FlightClientAPI from './src/ReactFlightClient';
11 +import typeof * as HostConfig from './src/ReactFlightClientConfig';
12 +
13 export * from './src/ReactFlightClient';
14 +
15 +// At build time, this module is wrapped as a factory function ($$$reconciler).
16 +// Consumers pass a host config object and get back the Flight client API.
17 +declare export default (hostConfig: HostConfig) => FlightClientAPI;
packages/react-client/src/forks/ReactFlightClientConfig.noop.js new
+57
@@ -0,0 +1,57 @@
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 +// This is a host config that's used for the internal `react-noop-renderer` package.
11 +//
12 +// Its API lets you pass the host config as an argument.
13 +// However, inside the `react-server` we treat host config as a module.
14 +// This file is a shim between two worlds.
15 +//
16 +// It works because the `react-server` bundle is wrapped in something like:
17 +//
18 +// module.exports = function ($$$config) {
19 +// /* renderer code */
20 +// }
21 +//
22 +// So `$$$config` looks like a global variable, but it's
23 +// really an argument to a top-level wrapping function.
24 +
25 +declare const $$$config: $FlowFixMe;
26 +
27 +export opaque type ModuleLoading = mixed;
28 +export opaque type ServerConsumerModuleMap = mixed;
29 +export opaque type ServerManifest = mixed;
30 +export opaque type ServerReferenceId = string;
31 +export opaque type ClientReferenceMetadata = mixed;
32 +export opaque type ClientReference<T> = mixed; // eslint-disable-line no-unused-vars
33 +export const resolveClientReference = $$$config.resolveClientReference;
34 +export const resolveServerReference = $$$config.resolveServerReference;
35 +export const preloadModule = $$$config.preloadModule;
36 +export const requireModule = $$$config.requireModule;
37 +export const getModuleDebugInfo = $$$config.getModuleDebugInfo;
38 +export const dispatchHint = $$$config.dispatchHint;
39 +export const prepareDestinationForModule =
40 + $$$config.prepareDestinationForModule;
41 +export const usedWithSSR = true;
42 +
43 +export opaque type Source = mixed;
44 +
45 +export opaque type StringDecoder = mixed;
46 +
47 +export const createStringDecoder = $$$config.createStringDecoder;
48 +export const readPartialStringChunk = $$$config.readPartialStringChunk;
49 +export const readFinalStringChunk = $$$config.readFinalStringChunk;
50 +
51 +export const bindToConsole = $$$config.bindToConsole;
52 +
53 +export const rendererVersion = $$$config.rendererVersion;
54 +export const rendererPackageName = $$$config.rendererPackageName;
55 +
56 +export const checkEvalAvailabilityOnceDev =
57 + $$$config.checkEvalAvailabilityOnceDev;
packages/react-noop-renderer/src/ReactFiberConfigNoop.js new
+33
@@ -0,0 +1,33 @@
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 +export type HostContext = Object;
11 +
12 +export type TextInstance = {
13 + text: string,
14 + id: number,
15 + parent: number,
16 + hidden: boolean,
17 + context: HostContext,
18 +};
19 +
20 +export type Instance = {
21 + type: string,
22 + id: number,
23 + parent: number,
24 + children: Array<Instance | TextInstance>,
25 + text: string | null,
26 + prop: any,
27 + hidden: boolean,
28 + context: HostContext,
29 +};
30 +
31 +export type PublicInstance = Instance;
32 +
33 +export type TransitionStatus = mixed;
packages/react-noop-renderer/src/ReactNoop.js
+1
@@ -53,6 +53,7 @@ export const {
53 getRoot,
54 // TODO: Remove this after callers migrate to alternatives.
55 unstable_runWithPriority,
56 + // $FlowFixMe[signature-verification-failure]
57 } = createReactNoop(
58 ReactFiberReconciler, // reconciler
59 true, // useMutation
packages/react-noop-renderer/src/ReactNoopFlightClient.js
+14 -2
@@ -14,6 +14,7 @@
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';
@@ -25,6 +26,7 @@ type Source = Array<Uint8Array>;
26 const decoderOptions = {stream: true};
27
28 const {createResponse, createStreamState, processBinaryChunk, getRoot, close} =
29 + // $FlowFixMe[prop-missing]
30 ReactFlightClient({
31 createStringDecoder() {
32 return new TextDecoder();
@@ -44,6 +46,7 @@ const {createResponse, createStreamState, processBinaryChunk, getRoot, close} =
46 return readModule(idx);
47 },
48 bindToConsole(methodName, args, badgeName) {
49 + // $FlowFixMe[incompatible-call]
50 return Function.prototype.bind.apply(
51 // eslint-disable-next-line react-internal/no-production-logging
52 console[methodName],
@@ -61,8 +64,10 @@ type ReadOptions = {|
64
65 function read<T>(source: Source, options: ReadOptions): Thenable<T> {
66 const response = createResponse(
67 + // $FlowFixMe[incompatible-call]
68 source,
69 null,
70 + // $FlowFixMe[incompatible-call]
71 null,
72 undefined,
73 undefined,
@@ -73,12 +78,19 @@ function read<T>(source: Source, options: ReadOptions): Thenable<T> {
78 true,
79 undefined,
80 __DEV__ && options !== undefined && options.debugChannel !== undefined
76 - ? options.debugChannel.onMessage
81 + ? // $FlowFixMe[incompatible-call]
82 + options.debugChannel.onMessage
83 : undefined,
84 );
85 const streamState = createStreamState(response, source);
86 for (let i = 0; i < source.length; i++) {
81 - processBinaryChunk(response, streamState, source[i], 0);
87 + processBinaryChunk(
88 + response,
89 + streamState,
90 + source[i],
91 + // $FlowFixMe[extra-arg]
92 + 0,
93 + );
94 }
95 if (options !== undefined && options.close) {
96 close(response);
packages/react-noop-renderer/src/ReactNoopFlightServer.js
+9 -2
@@ -20,10 +20,11 @@ import {saveModule} from 'react-noop-renderer/flight-modules';
20
21 import ReactFlightServer from 'react-server/flight';
22
23 -type Destination = Array<Uint8Array>;
23 +type Destination = Array<Uint8Array | string>;
24
25 const textEncoder = new TextEncoder();
26
27 +// $FlowFixMe[prop-missing]
28 const ReactNoopFlightServer = ReactFlightServer({
29 scheduleMicrotask(callback: () => void) {
30 callback();
@@ -81,6 +82,7 @@ function render(model: ReactClientValue, options?: Options): Destination {
82 const bundlerConfig = undefined;
83 const request = ReactNoopFlightServer.createRequest(
84 model,
85 + // $FlowFixMe[incompatible-call]
86 bundlerConfig,
87 options ? options.onError : undefined,
88 options ? options.identifierPrefix : undefined,
@@ -88,6 +90,7 @@ function render(model: ReactClientValue, options?: Options): Destination {
90 options ? options.startTime : undefined,
91 __DEV__ && options ? options.environmentName : undefined,
92 __DEV__ && options ? options.filterStackFrame : undefined,
93 + // $FlowFixMe[incompatible-call]
94 __DEV__ && options && options.debugChannel !== undefined,
95 );
96 const signal = options ? options.signal : undefined;
@@ -108,7 +111,11 @@ function render(model: ReactClientValue, options?: Options): Destination {
111 };
112 }
113 ReactNoopFlightServer.startWork(request);
111 - ReactNoopFlightServer.startFlowing(request, destination);
114 + ReactNoopFlightServer.startFlowing(
115 + request,
116 + // $FlowFixMe[incompatible-call]
117 + destination,
118 + );
119 return destination;
120 }
121
packages/react-noop-renderer/src/ReactNoopPersistent.js
+1
@@ -55,6 +55,7 @@ export const {
55 // TODO: Remove this once callers migrate to alternatives.
56 // This should only be used by React internals.
57 unstable_runWithPriority,
58 + // $FlowFixMe[signature-verification-failure]
59 } = createReactNoop(
60 ReactFiberReconciler, // reconciler
61 false, // useMutation
packages/react-noop-renderer/src/ReactNoopServer.js
+11 -3
@@ -40,12 +40,12 @@ type SuspenseInstance = {
40 };
41
42 type Placeholder = {
43 - parent: Instance | SuspenseInstance,
43 + parent: Instance | Segment | SuspenseInstance,
44 index: number,
45 };
46
47 type Segment = {
48 - children: null | Instance | TextInstance | SuspenseInstance,
48 + children: Array<Instance | TextInstance | SuspenseInstance>,
49 };
50
51 type Destination = {
@@ -79,6 +79,7 @@ function write(destination: Destination, buffer: Uint8Array): void {
79 stack.push(instance);
80 }
81
82 +// $FlowFixMe[prop-missing]
83 const ReactNoopServer = ReactFizzServer({
84 scheduleMicrotask(callback: () => void) {
85 callback();
@@ -175,6 +176,7 @@ const ReactNoopServer = ReactFizzServer({
176 destination: Destination,
177 renderState: RenderState,
178 id: number,
179 + // $FlowFixMe[incompatible-return]
180 ): boolean {
181 const parent = destination.stack[destination.stack.length - 1];
182 destination.placeholders.set(id, {
@@ -258,7 +260,7 @@ const ReactNoopServer = ReactFizzServer({
260 formatContext: null,
261 id: number,
262 ): boolean {
261 - const segment = {
263 + const segment: Segment = {
264 children: [],
265 };
266 destination.segments.set(id, segment);
@@ -314,6 +316,7 @@ const ReactNoopServer = ReactFizzServer({
316 renderState: RenderState,
317 boundary: SuspenseInstance,
318 ): boolean {
319 + // $FlowFixMe[prop-missing]
320 boundary.status = 'client-render';
321 return true;
322 },
@@ -357,6 +360,7 @@ type Options = {
360 };
361
362 function render(children: React$Element<any>, options?: Options): Destination {
363 + // $FlowFixMe[prop-missing]
364 const destination: Destination = {
365 root: null,
366 placeholders: new Map(),
@@ -368,8 +372,11 @@ function render(children: React$Element<any>, options?: Options): Destination {
372 };
373 const request = ReactNoopServer.createRequest(
374 children,
375 + // $FlowFixMe[incompatible-call]
376 null,
377 + // $FlowFixMe[incompatible-call]
378 null,
379 + // $FlowFixMe[incompatible-call]
380 null,
381 options ? options.progressiveChunkSize : undefined,
382 options ? options.onError : undefined,
@@ -377,6 +384,7 @@ function render(children: React$Element<any>, options?: Options): Destination {
384 options ? options.onShellReady : undefined,
385 );
386 ReactNoopServer.startWork(request);
387 + // $FlowFixMe[incompatible-call]
388 ReactNoopServer.startFlowing(request, destination);
389 return destination;
390 }
packages/react-noop-renderer/src/createReactNoop.js
+118 -47
@@ -23,6 +23,14 @@ import type {ReactNodeList} from 'shared/ReactTypes';
23 import type {RootTag} from 'react-reconciler/src/ReactRootTags';
24 import type {EventPriority} from 'react-reconciler/src/ReactEventPriorities';
25 import type {TransitionTypes} from 'react/src/ReactTransitionType';
26 +import typeof * as HostConfig from 'react-reconciler/src/ReactFiberConfig';
27 +import typeof * as ReconcilerAPI from 'react-reconciler/src/ReactFiberReconciler';
28 +import type {
29 + HostContext,
30 + Instance,
31 + PublicInstance,
32 + TextInstance,
33 +} from './ReactFiberConfigNoop';
34
35 import * as Scheduler from 'scheduler/unstable_mock';
36 import {REACT_FRAGMENT_TYPE, REACT_ELEMENT_TYPE} from 'shared/ReactSymbols';
@@ -58,28 +66,19 @@ type Props = {
66 src?: string,
67 ...
68 };
61 -type Instance = {
62 - type: string,
63 - id: number,
64 - parent: number,
65 - children: Array<Instance | TextInstance>,
66 - text: string | null,
67 - prop: any,
68 - hidden: boolean,
69 - context: HostContext,
70 -};
71 -type TextInstance = {
72 - text: string,
73 - id: number,
74 - parent: number,
75 - hidden: boolean,
76 - context: HostContext,
77 -};
78 -type HostContext = Object;
69 type CreateRootOptions = {
70 unstable_transitionCallbacks?: TransitionTracingCallbacks,
81 - onUncaughtError?: (error: mixed, errorInfo: {componentStack: string}) => void,
82 - onCaughtError?: (error: mixed, errorInfo: {componentStack: string}) => void,
71 + onUncaughtError?: (
72 + error: mixed,
73 + errorInfo: {+componentStack: ?string},
74 + ) => void,
75 + onCaughtError?: (
76 + error: mixed,
77 + errorInfo: {
78 + +componentStack: ?string,
79 + +errorBoundary?: ?component(...props: any),
80 + },
81 + ) => void,
82 onDefaultTransitionIndicator?: () => void | (() => void),
83 ...
84 };
@@ -108,7 +107,11 @@ if (__DEV__) {
107 Object.freeze(NO_CONTEXT);
108 }
109
111 -function createReactNoop(reconciler: Function, useMutation: boolean) {
110 +// $FlowFixMe[signature-verification-failure]
111 +function createReactNoop(
112 + reconciler: (hostConfig: HostConfig) => ReconcilerAPI,
113 + useMutation: boolean,
114 +): any {
115 let instanceCounter = 0;
116 let hostUpdateCounter = 0;
117 let hostCloneCounter = 0;
@@ -118,9 +121,11 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
121 child: Instance | TextInstance,
122 ): void {
123 const prevParent = child.parent;
124 + // $FlowFixMe[prop-missing]
125 if (prevParent !== -1 && prevParent !== parentInstance.id) {
126 throw new Error('Reparenting is not allowed');
127 }
128 + // $FlowFixMe[prop-missing]
129 child.parent = parentInstance.id;
130 const index = parentInstance.children.indexOf(child);
131 if (index !== -1) {
@@ -265,6 +270,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
270 };
271
272 if (type === 'suspensey-thing' && typeof newProps.src === 'string') {
273 + // $FlowFixMe[prop-missing]
274 clone.src = newProps.src;
275 }
276
@@ -285,6 +291,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
291 enumerable: false,
292 });
293 hostCloneCounter++;
294 + // $FlowFixMe[incompatible-return]
295 return clone;
296 }
297
@@ -299,7 +306,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
306 );
307 }
308
302 - function computeText(rawText, hostContext) {
309 + function computeText(rawText: string, hostContext: HostContext) {
310 return hostContext === UPPERCASE_CONTEXT ? rawText.toUpperCase() : rawText;
311 }
312
@@ -333,6 +340,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
340 // Attach a listener to the suspensey thing and create a subscription
341 // object that uses reference counting to track when all the suspensey
342 // things have loaded.
343 + // $FlowFixMe
344 const record = suspenseyThingCache.get(src);
345 if (record === undefined) {
346 throw new Error('Could not find record for key.');
@@ -344,8 +352,10 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
352 // Stash the subscription on the record. In `resolveSuspenseyThing`,
353 // we'll use this fire the commit once all the things have loaded.
354 if (record.subscriptions === null) {
355 + // $FlowFixMe[incompatible-use]
356 record.subscriptions = [];
357 }
358 + // $FlowFixMe[incompatible-use]
359 record.subscriptions.push(state);
360 }
361 } else {
@@ -361,7 +371,8 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
371 timeoutOffset: number,
372 ): ((commit: () => mixed) => () => void) | null {
373 if (state.pendingCount > 0) {
364 - return (commit: () => void) => {
374 + return (commit: () => mixed) => {
375 + // $FlowFixMe[incompatible-type]
376 state.commit = commit;
377 const cancelCommit = () => {
378 state.commit = null;
@@ -392,8 +403,8 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
403 return NO_CONTEXT;
404 },
405
395 - getPublicInstance(instance) {
396 - return instance;
406 + getPublicInstance(instance: Instance): PublicInstance {
407 + return (instance: any);
408 },
409
410 createInstance(
@@ -413,7 +424,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
424 checkPropStringCoercion(props.children, 'children');
425 }
426 }
416 - const inst = {
427 + const inst: Instance = {
428 id: instanceCounter++,
429 type: type,
430 children: [],
@@ -428,6 +439,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
439 };
440
441 if (type === 'suspensey-thing' && typeof props.src === 'string') {
442 + // $FlowFixMe[prop-missing]
443 inst.src = props.src;
444 }
445
@@ -445,10 +457,12 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
457 value: inst.context,
458 enumerable: false,
459 });
460 + // $FlowFixMe[prop-missing]
461 Object.defineProperty(inst, 'fiber', {
462 value: internalInstanceHandle,
463 enumerable: false,
464 });
465 + // $FlowFixMe[incompatible-return]
466 return inst;
467 },
468
@@ -511,19 +525,19 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
525 throw new Error('Not yet implemented.');
526 },
527
514 - createFragmentInstance(fragmentFiber) {
528 + createFragmentInstance(fragmentFiber: mixed) {
529 return null;
530 },
531
518 - updateFragmentInstanceFiber(fragmentFiber, fragmentInstance) {
532 + updateFragmentInstanceFiber(fragmentFiber: mixed, fragmentInstance: mixed) {
533 // Noop
534 },
535
522 - commitNewChildToFragmentInstance(child, fragmentInstance) {
536 + commitNewChildToFragmentInstance(child: mixed, fragmentInstance: mixed) {
537 // Noop
538 },
539
526 - deleteChildFromFragmentInstance(child, fragmentInstance) {
540 + deleteChildFromFragmentInstance(child: mixed, fragmentInstance: mixed) {
541 // Noop
542 },
543
@@ -536,7 +550,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
550 typeof queueMicrotask === 'function'
551 ? queueMicrotask
552 : typeof Promise !== 'undefined'
539 - ? callback =>
553 + ? (callback: () => void) =>
554 Promise.resolve(null)
555 .then(callback)
556 .catch(error => {
@@ -610,7 +624,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
624 // no-op
625 },
626
613 - requestPostPaintCallback(callback) {
627 + requestPostPaintCallback(callback: (time: number) => void) {
628 const endTime = Scheduler.unstable_now();
629 callback(endTime);
630 },
@@ -661,19 +675,23 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
675 if (suspenseyThingCache === null) {
676 suspenseyThingCache = new Map();
677 }
678 + // $FlowFixMe
679 const record = suspenseyThingCache.get(props.src);
680 if (record === undefined) {
681 const newRecord: SuspenseyThingRecord = {
682 status: 'pending',
683 subscriptions: null,
684 };
685 + // $FlowFixMe
686 suspenseyThingCache.set(props.src, newRecord);
687 + // $FlowFixMe[prop-missing]
688 const onLoadStart = props.onLoadStart;
689 if (typeof onLoadStart === 'function') {
690 onLoadStart();
691 }
692 return false;
693 } else {
694 + // $FlowFixMe[prop-missing]
695 return record.status === 'fulfilled';
696 }
697 },
@@ -713,7 +731,8 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
731
732 resetFormInstance(form: Instance) {},
733
716 - bindToConsole(methodName, args, badgeName) {
734 + bindToConsole(methodName: $FlowFixMe, args: Array<any>, badgeName: string) {
735 + // $FlowFixMe[incompatible-call]
736 return Function.prototype.bind.apply(
737 // eslint-disable-next-line react-internal/no-production-logging
738 console[methodName],
@@ -722,8 +741,9 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
741 },
742 };
743
725 - const hostConfig = useMutation
726 - ? {
744 + const hostConfig: HostConfig = useMutation
745 + ? // $FlowFixMe[prop-missing]
746 + {
747 ...sharedHostConfig,
748
749 supportsMutation: true,
@@ -747,6 +767,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
767 instance.hidden = !!newProps.hidden;
768
769 if (type === 'suspensey-thing' && typeof newProps.src === 'string') {
770 + // $FlowFixMe[prop-missing]
771 instance.src = newProps.src;
772 }
773
@@ -907,7 +928,8 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
928 instance.text = null;
929 },
930 }
910 - : {
931 + : // $FlowFixMe[prop-missing]
932 + {
933 ...sharedHostConfig,
934 supportsMutation: false,
935 supportsPersistence: true,
@@ -987,8 +1009,8 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1009
1010 const NoopRenderer = reconciler(hostConfig);
1011
990 - const rootContainers = new Map();
991 - const roots = new Map();
1012 + const rootContainers = new Map<string, Container>();
1013 + const roots = new Map<string, Object>();
1014 const DEFAULT_ROOT_ID = '<default>';
1015
1016 let currentUpdatePriority = NoEventPriority;
@@ -1002,6 +1024,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1024
1025 let currentEventPriority = DefaultEventPriority;
1026
1027 + // $FlowFixMe[missing-local-annot]
1028 function createJSXElementForTestComparison(type, props) {
1029 if (__DEV__) {
1030 const element = {
@@ -1012,6 +1035,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1035 _owner: null,
1036 _store: __DEV__ ? {} : undefined,
1037 };
1038 + // $FlowFixMe[prop-missing]
1039 Object.defineProperty(element, 'ref', {
1040 enumerable: false,
1041 value: null,
@@ -1028,6 +1052,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1052 }
1053 }
1054
1055 + // $FlowFixMe
1056 function childToJSX(child, text) {
1057 if (text !== null) {
1058 return text;
@@ -1066,6 +1091,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1091 if (instance.hidden) {
1092 props.hidden = true;
1093 }
1094 + // $FlowFixMe[prop-missing]
1095 if (instance.src) {
1096 props.src = instance.src;
1097 }
@@ -1082,6 +1108,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1108 return textInstance.text;
1109 }
1110
1111 + // $FlowFixMe[missing-local-annot]
1112 function getChildren(root) {
1113 if (root) {
1114 return root.children;
@@ -1090,6 +1117,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1117 }
1118 }
1119
1120 + // $FlowFixMe[missing-local-annot]
1121 function getPendingChildren(root) {
1122 if (root) {
1123 return root.children;
@@ -1098,6 +1126,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1126 }
1127 }
1128
1129 + // $FlowFixMe[missing-local-annot]
1130 function getChildrenAsJSX(root) {
1131 const children = childToJSX(getChildren(root), null);
1132 if (children === null) {
@@ -1109,6 +1138,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1138 return children;
1139 }
1140
1141 + // $FlowFixMe[missing-local-annot]
1142 function getPendingChildrenAsJSX(root) {
1143 const children = childToJSX(getChildren(root), null);
1144 if (children === null) {
@@ -1139,6 +1169,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1169 if (fn) {
1170 return fn();
1171 } else {
1172 + // $FlowFixMe[incompatible-return]
1173 return undefined;
1174 }
1175 } finally {
@@ -1159,6 +1190,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1190
1191 let idCounter = 0;
1192
1193 + // $FlowFixMe
1194 const ReactNoop = {
1195 _Scheduler: Scheduler,
1196
@@ -1199,12 +1231,19 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1231 getOrCreateRootContainer(rootID: string = DEFAULT_ROOT_ID, tag: RootTag) {
1232 let root = roots.get(rootID);
1233 if (!root) {
1202 - const container = {rootID: rootID, pendingChildren: [], children: []};
1234 + const container: Container = {
1235 + rootID: rootID,
1236 + pendingChildren: [],
1237 + children: [],
1238 + };
1239 + // $FlowFixMe[incompatible-call]
1240 rootContainers.set(rootID, container);
1241 root = NoopRenderer.createContainer(
1242 + // $FlowFixMe[incompatible-call] -- Discovered when typechecking noop-renderer
1243 container,
1244 tag,
1245 null,
1246 + // $FlowFixMe[incompatible-call] -- Discovered when typechecking noop-renderer
1247 null,
1248 false,
1249 '',
@@ -1221,15 +1260,17 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1260
1261 // TODO: Replace ReactNoop.render with createRoot + root.render
1262 createRoot(options?: CreateRootOptions) {
1224 - const container = {
1263 + const container: Container = {
1264 rootID: '' + idCounter++,
1265 pendingChildren: [],
1266 children: [],
1267 };
1268 const fiberRoot = NoopRenderer.createContainer(
1269 + // $FlowFixMe[incompatible-call]
1270 container,
1271 ConcurrentRoot,
1272 null,
1273 + // $FlowFixMe[incompatible-call]
1274 null,
1275 false,
1276 '',
@@ -1272,9 +1313,11 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1313 children: [],
1314 };
1315 const fiberRoot = NoopRenderer.createContainer(
1316 + // $FlowFixMe[incompatible-call] -- TODO: Discovered when typechecking noop-renderer
1317 container,
1318 LegacyRoot,
1319 null,
1320 + // $FlowFixMe[incompatible-call] -- TODO: Discovered when typechecking noop-renderer
1321 null,
1322 false,
1323 '',
@@ -1309,11 +1352,13 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1352 return getPendingChildrenAsJSX(container);
1353 },
1354
1355 + // $FlowFixMe[missing-local-annot]
1356 getSuspenseyThingStatus(src): string | null {
1357 if (suspenseyThingCache === null) {
1358 return null;
1359 } else {
1360 const record = suspenseyThingCache.get(src);
1361 + // $FlowFixMe[prop-missing]
1362 return record === undefined ? null : record.status;
1363 }
1364 },
@@ -1322,18 +1367,24 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1367 if (suspenseyThingCache === null) {
1368 suspenseyThingCache = new Map();
1369 }
1370 + // $FlowFixMe[incompatible-call]
1371 const record = suspenseyThingCache.get(key);
1372 if (record === undefined) {
1373 const newRecord: SuspenseyThingRecord = {
1374 status: 'fulfilled',
1375 subscriptions: null,
1376 };
1377 + // $FlowFixMe
1378 suspenseyThingCache.set(key, newRecord);
1379 } else {
1380 + // $FlowFixMe[prop-missing]
1381 if (record.status === 'pending') {
1382 + // $FlowFixMe[incompatible-use]
1383 record.status = 'fulfilled';
1384 + // $FlowFixMe[prop-missing]
1385 const subscriptions = record.subscriptions;
1386 if (subscriptions !== null) {
1387 + // $FlowFixMe[incompatible-use]
1388 record.subscriptions = null;
1389 for (let i = 0; i < subscriptions.length; i++) {
1390 const subscription = subscriptions[i];
@@ -1411,11 +1462,13 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1462 return component;
1463 }
1464 if (__DEV__) {
1465 + // $FlowFixMe[incompatible-return]
1466 return NoopRenderer.findHostInstanceWithWarning(
1467 component,
1468 'findInstance',
1469 );
1470 }
1471 + // $FlowFixMe[incompatible-return]
1472 return NoopRenderer.findHostInstance(component);
1473 },
1474
@@ -1474,6 +1527,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1527
1528 discreteUpdates: NoopRenderer.discreteUpdates,
1529
1530 + // $FlowFixMe[incompatible-return]
1531 idleUpdates<T>(fn: () => T): T {
1532 const prevEventPriority = currentEventPriority;
1533 currentEventPriority = IdleEventPriority;
@@ -1497,14 +1551,16 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1551 return;
1552 }
1553
1500 - const bufferedLog = [];
1501 - function log(...args) {
1554 + const bufferedLog: string[] = [];
1555 + // $FlowFixMe[missing-local-annot]
1556 + function log(...args: string[]) {
1557 + // $FlowFixMe[incompatible-call]
1558 bufferedLog.push(...args, '\n');
1559 }
1560
1561 function logHostInstances(
1562 children: Array<Instance | TextInstance>,
1507 - depth,
1563 + depth: number,
1564 ) {
1565 for (let i = 0; i < children.length; i++) {
1566 const child = children[i];
@@ -1512,17 +1568,23 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1568 if (typeof child.text === 'string') {
1569 log(indent + '- ' + child.text);
1570 } else {
1571 + // $FlowFixMe[unsafe-addition]
1572 log(indent + '- ' + child.type + '#' + child.id);
1516 - logHostInstances(child.children, depth + 1);
1573 +
1574 + logHostInstances(
1575 + // $FlowFixMe[incompatible-call]
1576 + child.children,
1577 + depth + 1,
1578 + );
1579 }
1580 }
1581 }
1520 - function logContainer(container: Container, depth) {
1582 + function logContainer(container: Container, depth: number) {
1583 log(' '.repeat(depth) + '- [root#' + container.rootID + ']');
1584 logHostInstances(container.children, depth + 1);
1585 }
1586
1525 - function logUpdateQueue(updateQueue: UpdateQueue<mixed>, depth) {
1587 + function logUpdateQueue(updateQueue: UpdateQueue<mixed>, depth: number) {
1588 log(' '.repeat(depth + 1) + 'QUEUED UPDATES');
1589 const first = updateQueue.firstBaseUpdate;
1590 const update = first;
@@ -1530,6 +1592,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1592 do {
1593 log(
1594 ' '.repeat(depth + 1) + '~',
1595 + // $FlowFixMe
1596 '[' + update.expirationTime + ']',
1597 );
1598 } while (update !== null);
@@ -1543,6 +1606,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1606 do {
1607 log(
1608 ' '.repeat(depth + 1) + '~',
1609 + // $FlowFixMe
1610 '[' + pendingUpdate.expirationTime + ']',
1611 );
1612 } while (pendingUpdate !== null && pendingUpdate !== firstPending);
@@ -1550,19 +1614,26 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
1614 }
1615 }
1616
1617 + // $FlowFixMe[missing-local-annot]
1618 function logFiber(fiber: Fiber, depth) {
1619 log(
1620 ' '.repeat(depth) +
1621 '- ' +
1622 // need to explicitly coerce Symbol to a string
1623 (fiber.type ? fiber.type.name || fiber.type.toString() : '[root]'),
1624 + // $FlowFixMe[unsafe-addition]
1625 '[' +
1626 + // $FlowFixMe[prop-missing]
1627 fiber.childExpirationTime +
1628 (fiber.pendingProps ? '*' : '') +
1629 ']',
1630 );
1631 if (fiber.updateQueue) {
1565 - logUpdateQueue(fiber.updateQueue, depth);
1632 + logUpdateQueue(
1633 + // $FlowFixMe[incompatible-call]
1634 + fiber.updateQueue,
1635 + depth,
1636 + );
1637 }
1638 // const childInProgress = fiber.progressedChild;
1639 // if (childInProgress && childInProgress !== fiber.child) {
packages/react-reconciler/index.js
+7
@@ -7,4 +7,11 @@
7 * @flow
8 */
9
10 +import typeof * as ReconcilerAPI from './src/ReactFiberReconciler';
11 +import typeof * as HostConfig from './src/ReactFiberConfig';
12 +
13 export * from './src/ReactFiberReconciler';
14 +
15 +// At build time, this module is wrapped as a factory function ($$$reconciler).
16 +// Consumers pass a host config object and get back the reconciler API.
17 +declare export default (hostConfig: HostConfig) => ReconcilerAPI;
packages/react-reconciler/src/forks/ReactFiberConfig.noop.js new
+282
@@ -0,0 +1,282 @@
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 +// This is a host config that's used for the internal `react-noop-renderer`.
11 +//
12 +// Its API lets you pass the host config as an argument.
13 +// However, inside the `react-reconciler` we treat host config as a module.
14 +// This file is a shim between two worlds.
15 +//
16 +// It works because the `react-reconciler` bundle is wrapped in something like:
17 +//
18 +// module.exports = function ($$$config) {
19 +// /* reconciler code */
20 +// }
21 +//
22 +// So `$$$config` looks like a global variable, but it's
23 +// really an argument to a top-level wrapping function.
24 +
25 +export * from 'react-noop-renderer/src/ReactFiberConfigNoop';
26 +
27 +declare const $$$config: $FlowFixMe;
28 +export opaque type Type = mixed;
29 +export opaque type Props = mixed;
30 +export opaque type Container = mixed;
31 +export opaque type ActivityInstance = mixed;
32 +export opaque type SuspenseInstance = mixed;
33 +export opaque type HydratableInstance = mixed;
34 +export opaque type UpdatePayload = mixed;
35 +export opaque type ChildSet = mixed;
36 +export opaque type TimeoutHandle = mixed;
37 +export opaque type NoTimeout = mixed;
38 +export opaque type RendererInspectionConfig = mixed;
39 +export opaque type FormInstance = mixed;
40 +export opaque type SuspendedState = mixed;
41 +export type RunningViewTransition = mixed;
42 +export type ViewTransitionInstance = null | {name: string, ...};
43 +export opaque type InstanceMeasurement = mixed;
44 +export type EventResponder = any;
45 +export type GestureTimeline = any;
46 +export type FragmentInstanceType = null;
47 +
48 +export const rendererVersion = $$$config.rendererVersion;
49 +export const rendererPackageName = $$$config.rendererPackageName;
50 +export const extraDevToolsConfig = $$$config.extraDevToolsConfig;
51 +
52 +export const getPublicInstance = $$$config.getPublicInstance;
53 +export const getRootHostContext = $$$config.getRootHostContext;
54 +export const getChildHostContext = $$$config.getChildHostContext;
55 +export const prepareForCommit = $$$config.prepareForCommit;
56 +export const resetAfterCommit = $$$config.resetAfterCommit;
57 +export const createInstance = $$$config.createInstance;
58 +export const cloneMutableInstance = $$$config.cloneMutableInstance;
59 +export const appendInitialChild = $$$config.appendInitialChild;
60 +export const finalizeInitialChildren = $$$config.finalizeInitialChildren;
61 +export const shouldSetTextContent = $$$config.shouldSetTextContent;
62 +export const createTextInstance = $$$config.createTextInstance;
63 +export const cloneMutableTextInstance = $$$config.cloneMutableTextInstance;
64 +export const scheduleTimeout = $$$config.scheduleTimeout;
65 +export const cancelTimeout = $$$config.cancelTimeout;
66 +export const noTimeout = $$$config.noTimeout;
67 +export const isPrimaryRenderer = $$$config.isPrimaryRenderer;
68 +export const warnsIfNotActing = $$$config.warnsIfNotActing;
69 +export const supportsMutation = $$$config.supportsMutation;
70 +export const supportsPersistence = $$$config.supportsPersistence;
71 +export const supportsHydration = $$$config.supportsHydration;
72 +export const getInstanceFromNode = $$$config.getInstanceFromNode;
73 +export const beforeActiveInstanceBlur = $$$config.beforeActiveInstanceBlur;
74 +export const afterActiveInstanceBlur = $$$config.afterActiveInstanceBlur;
75 +export const preparePortalMount = $$$config.preparePortalMount;
76 +export const prepareScopeUpdate = $$$config.prepareScopeUpdate;
77 +export const getInstanceFromScope = $$$config.getInstanceFromScope;
78 +export const setCurrentUpdatePriority = $$$config.setCurrentUpdatePriority;
79 +export const getCurrentUpdatePriority = $$$config.getCurrentUpdatePriority;
80 +export const resolveUpdatePriority = $$$config.resolveUpdatePriority;
81 +export const trackSchedulerEvent = $$$config.trackSchedulerEvent;
82 +export const resolveEventType = $$$config.resolveEventType;
83 +export const resolveEventTimeStamp = $$$config.resolveEventTimeStamp;
84 +export const shouldAttemptEagerTransition =
85 + $$$config.shouldAttemptEagerTransition;
86 +export const detachDeletedInstance = $$$config.detachDeletedInstance;
87 +export const requestPostPaintCallback = $$$config.requestPostPaintCallback;
88 +export const maySuspendCommit = $$$config.maySuspendCommit;
89 +export const maySuspendCommitOnUpdate = $$$config.maySuspendCommitOnUpdate;
90 +export const maySuspendCommitInSyncRender =
91 + $$$config.maySuspendCommitInSyncRender;
92 +export const preloadInstance = $$$config.preloadInstance;
93 +export const startSuspendingCommit = $$$config.startSuspendingCommit;
94 +export const suspendInstance = $$$config.suspendInstance;
95 +export const suspendOnActiveViewTransition =
96 + $$$config.suspendOnActiveViewTransition;
97 +export const waitForCommitToBeReady = $$$config.waitForCommitToBeReady;
98 +export const getSuspendedCommitReason = $$$config.getSuspendedCommitReason;
99 +export const NotPendingTransition = $$$config.NotPendingTransition;
100 +export const HostTransitionContext = $$$config.HostTransitionContext;
101 +export const resetFormInstance = $$$config.resetFormInstance;
102 +export const bindToConsole = $$$config.bindToConsole;
103 +
104 +// -------------------
105 +// Microtasks
106 +// (optional)
107 +// -------------------
108 +export const supportsMicrotasks = $$$config.supportsMicrotasks;
109 +export const scheduleMicrotask = $$$config.scheduleMicrotask;
110 +
111 +// -------------------
112 +// Test selectors
113 +// (optional)
114 +// -------------------
115 +export const supportsTestSelectors = $$$config.supportsTestSelectors;
116 +export const findFiberRoot = $$$config.findFiberRoot;
117 +export const getBoundingRect = $$$config.getBoundingRect;
118 +export const getTextContent = $$$config.getTextContent;
119 +export const isHiddenSubtree = $$$config.isHiddenSubtree;
120 +export const matchAccessibilityRole = $$$config.matchAccessibilityRole;
121 +export const setFocusIfFocusable = $$$config.setFocusIfFocusable;
122 +export const setupIntersectionObserver = $$$config.setupIntersectionObserver;
123 +
124 +// -------------------
125 +// Mutation
126 +// (optional)
127 +// -------------------
128 +export const appendChild = $$$config.appendChild;
129 +export const appendChildToContainer = $$$config.appendChildToContainer;
130 +export const commitTextUpdate = $$$config.commitTextUpdate;
131 +export const commitMount = $$$config.commitMount;
132 +export const commitUpdate = $$$config.commitUpdate;
133 +export const insertBefore = $$$config.insertBefore;
134 +export const insertInContainerBefore = $$$config.insertInContainerBefore;
135 +export const removeChild = $$$config.removeChild;
136 +export const removeChildFromContainer = $$$config.removeChildFromContainer;
137 +export const resetTextContent = $$$config.resetTextContent;
138 +export const hideInstance = $$$config.hideInstance;
139 +export const hideTextInstance = $$$config.hideTextInstance;
140 +export const unhideInstance = $$$config.unhideInstance;
141 +export const unhideTextInstance = $$$config.unhideTextInstance;
142 +export const applyViewTransitionName = $$$config.applyViewTransitionName;
143 +export const restoreViewTransitionName = $$$config.restoreViewTransitionName;
144 +export const cancelViewTransitionName = $$$config.cancelViewTransitionName;
145 +export const cancelRootViewTransitionName =
146 + $$$config.cancelRootViewTransitionName;
147 +export const restoreRootViewTransitionName =
148 + $$$config.restoreRootViewTransitionName;
149 +export const cloneRootViewTransitionContainer =
150 + $$$config.cloneRootViewTransitionContainer;
151 +export const removeRootViewTransitionClone =
152 + $$$config.removeRootViewTransitionClone;
153 +export const measureInstance = $$$config.measureInstance;
154 +export const measureClonedInstance = $$$config.measureClonedInstance;
155 +export const wasInstanceInViewport = $$$config.wasInstanceInViewport;
156 +export const hasInstanceChanged = $$$config.hasInstanceChanged;
157 +export const hasInstanceAffectedParent = $$$config.hasInstanceAffectedParent;
158 +export const startViewTransition = $$$config.startViewTransition;
159 +export const startGestureTransition = $$$config.startGestureTransition;
160 +export const stopViewTransition = $$$config.stopViewTransition;
161 +export const addViewTransitionFinishedListener =
162 + $$$config.addViewTransitionFinishedListener;
163 +export const getCurrentGestureOffset = $$$config.getCurrentGestureOffset;
164 +export const createViewTransitionInstance =
165 + $$$config.createViewTransitionInstance;
166 +export const clearContainer = $$$config.clearContainer;
167 +export const createFragmentInstance = $$$config.createFragmentInstance;
168 +export const updateFragmentInstanceFiber =
169 + $$$config.updateFragmentInstanceFiber;
170 +export const commitNewChildToFragmentInstance =
171 + $$$config.commitNewChildToFragmentInstance;
172 +export const deleteChildFromFragmentInstance =
173 + $$$config.deleteChildFromFragmentInstance;
174 +
175 +// -------------------
176 +// Persistence
177 +// (optional)
178 +// -------------------
179 +export const cloneInstance = $$$config.cloneInstance;
180 +export const createContainerChildSet = $$$config.createContainerChildSet;
181 +export const appendChildToContainerChildSet =
182 + $$$config.appendChildToContainerChildSet;
183 +export const finalizeContainerChildren = $$$config.finalizeContainerChildren;
184 +export const replaceContainerChildren = $$$config.replaceContainerChildren;
185 +export const cloneHiddenInstance = $$$config.cloneHiddenInstance;
186 +export const cloneHiddenTextInstance = $$$config.cloneHiddenTextInstance;
187 +
188 +// -------------------
189 +// Hydration
190 +// (optional)
191 +// -------------------
192 +export const isSuspenseInstancePending = $$$config.isSuspenseInstancePending;
193 +export const isSuspenseInstanceFallback = $$$config.isSuspenseInstanceFallback;
194 +export const getSuspenseInstanceFallbackErrorDetails =
195 + $$$config.getSuspenseInstanceFallbackErrorDetails;
196 +export const registerSuspenseInstanceRetry =
197 + $$$config.registerSuspenseInstanceRetry;
198 +export const canHydrateFormStateMarker = $$$config.canHydrateFormStateMarker;
199 +export const isFormStateMarkerMatching = $$$config.isFormStateMarkerMatching;
200 +export const getNextHydratableSibling = $$$config.getNextHydratableSibling;
201 +export const getNextHydratableSiblingAfterSingleton =
202 + $$$config.getNextHydratableSiblingAfterSingleton;
203 +export const getFirstHydratableChild = $$$config.getFirstHydratableChild;
204 +export const getFirstHydratableChildWithinContainer =
205 + $$$config.getFirstHydratableChildWithinContainer;
206 +export const getFirstHydratableChildWithinActivityInstance =
207 + $$$config.getFirstHydratableChildWithinActivityInstance;
208 +export const getFirstHydratableChildWithinSuspenseInstance =
209 + $$$config.getFirstHydratableChildWithinSuspenseInstance;
210 +export const getFirstHydratableChildWithinSingleton =
211 + $$$config.getFirstHydratableChildWithinSingleton;
212 +export const canHydrateInstance = $$$config.canHydrateInstance;
213 +export const canHydrateTextInstance = $$$config.canHydrateTextInstance;
214 +export const canHydrateActivityInstance = $$$config.canHydrateActivityInstance;
215 +export const canHydrateSuspenseInstance = $$$config.canHydrateSuspenseInstance;
216 +export const hydrateInstance = $$$config.hydrateInstance;
217 +export const hydrateTextInstance = $$$config.hydrateTextInstance;
218 +export const hydrateActivityInstance = $$$config.hydrateActivityInstance;
219 +export const hydrateSuspenseInstance = $$$config.hydrateSuspenseInstance;
220 +export const getNextHydratableInstanceAfterActivityInstance =
221 + $$$config.getNextHydratableInstanceAfterActivityInstance;
222 +export const getNextHydratableInstanceAfterSuspenseInstance =
223 + $$$config.getNextHydratableInstanceAfterSuspenseInstance;
224 +export const commitHydratedInstance = $$$config.commitHydratedInstance;
225 +export const commitHydratedContainer = $$$config.commitHydratedContainer;
226 +export const commitHydratedActivityInstance =
227 + $$$config.commitHydratedActivityInstance;
228 +export const commitHydratedSuspenseInstance =
229 + $$$config.commitHydratedSuspenseInstance;
230 +export const finalizeHydratedChildren = $$$config.finalizeHydratedChildren;
231 +export const flushHydrationEvents = $$$config.flushHydrationEvents;
232 +export const clearActivityBoundary = $$$config.clearActivityBoundary;
233 +export const clearSuspenseBoundary = $$$config.clearSuspenseBoundary;
234 +export const clearActivityBoundaryFromContainer =
235 + $$$config.clearActivityBoundaryFromContainer;
236 +export const clearSuspenseBoundaryFromContainer =
237 + $$$config.clearSuspenseBoundaryFromContainer;
238 +export const hideDehydratedBoundary = $$$config.hideDehydratedBoundary;
239 +export const unhideDehydratedBoundary = $$$config.unhideDehydratedBoundary;
240 +export const shouldDeleteUnhydratedTailInstances =
241 + $$$config.shouldDeleteUnhydratedTailInstances;
242 +export const diffHydratedPropsForDevWarnings =
243 + $$$config.diffHydratedPropsForDevWarnings;
244 +export const diffHydratedTextForDevWarnings =
245 + $$$config.diffHydratedTextForDevWarnings;
246 +export const describeHydratableInstanceForDevWarnings =
247 + $$$config.describeHydratableInstanceForDevWarnings;
248 +export const validateHydratableInstance = $$$config.validateHydratableInstance;
249 +export const validateHydratableTextInstance =
250 + $$$config.validateHydratableTextInstance;
251 +
252 +// -------------------
253 +// Resources
254 +// (optional)
255 +// -------------------
256 +export type HoistableRoot = mixed;
257 +export type Resource = mixed;
258 +export const supportsResources = $$$config.supportsResources;
259 +export const isHostHoistableType = $$$config.isHostHoistableType;
260 +export const getHoistableRoot = $$$config.getHoistableRoot;
261 +export const getResource = $$$config.getResource;
262 +export const acquireResource = $$$config.acquireResource;
263 +export const releaseResource = $$$config.releaseResource;
264 +export const hydrateHoistable = $$$config.hydrateHoistable;
265 +export const mountHoistable = $$$config.mountHoistable;
266 +export const unmountHoistable = $$$config.unmountHoistable;
267 +export const createHoistableInstance = $$$config.createHoistableInstance;
268 +export const prepareToCommitHoistables = $$$config.prepareToCommitHoistables;
269 +export const mayResourceSuspendCommit = $$$config.mayResourceSuspendCommit;
270 +export const preloadResource = $$$config.preloadResource;
271 +export const suspendResource = $$$config.suspendResource;
272 +
273 +// -------------------
274 +// Singletons
275 +// (optional)
276 +// -------------------
277 +export const supportsSingletons = $$$config.supportsSingletons;
278 +export const resolveSingletonInstance = $$$config.resolveSingletonInstance;
279 +export const acquireSingletonInstance = $$$config.acquireSingletonInstance;
280 +export const releaseSingletonInstance = $$$config.releaseSingletonInstance;
281 +export const isHostSingletonType = $$$config.isHostSingletonType;
282 +export const isSingletonScope = $$$config.isSingletonScope;
packages/react-server/flight.js
+7
@@ -7,4 +7,11 @@
7 * @flow
8 */
9
10 +import typeof * as FlightServerAPI from './src/ReactFlightServer';
11 +import typeof * as HostConfig from './src/ReactFlightServerConfig';
12 +
13 export * from './src/ReactFlightServer';
14 +
15 +// At build time, this module is wrapped as a factory function ($$$reconciler).
16 +// Consumers pass a host config object and get back the Flight server API.
17 +declare export default (hostConfig: HostConfig) => FlightServerAPI;
packages/react-server/index.js
+7
@@ -7,4 +7,11 @@
7 * @flow
8 */
9
10 +import typeof * as FizzAPI from './src/ReactFizzServer';
11 +import typeof * as HostConfig from './src/ReactFizzConfig';
12 +
13 export * from './src/ReactFizzServer';
14 +
15 +// At build time, this module is wrapped as a factory function ($$$reconciler).
16 +// Consumers pass a host config object and get back the Fizz server API.
17 +declare export default (hostConfig: HostConfig) => FizzAPI;
packages/react-server/src/forks/ReactFizzConfig.noop.js new
+108
@@ -0,0 +1,108 @@
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 +// This is a host config that's used for the `react-server` package on npm.
11 +// It is only used by third-party renderers.
12 +//
13 +// Its API lets you pass the host config as an argument.
14 +// However, inside the `react-server` we treat host config as a module.
15 +// This file is a shim between two worlds.
16 +//
17 +// It works because the `react-server` bundle is wrapped in something like:
18 +//
19 +// module.exports = function ($$$config) {
20 +// /* renderer code */
21 +// }
22 +//
23 +// So `$$$config` looks like a global variable, but it's
24 +// really an argument to a top-level wrapping function.
25 +
26 +import type {Request} from 'react-server/src/ReactFizzServer';
27 +import type {TransitionStatus} from 'react-reconciler/src/ReactFiberConfig';
28 +
29 +declare const $$$config: $FlowFixMe;
30 +export opaque type Destination = mixed;
31 +export opaque type RenderState = mixed;
32 +export opaque type HoistableState = mixed;
33 +export opaque type ResumableState = mixed;
34 +export opaque type PreambleState = mixed;
35 +export opaque type FormatContext = mixed;
36 +export opaque type HeadersDescriptor = mixed;
37 +export type {TransitionStatus};
38 +
39 +export const isPrimaryRenderer = false;
40 +
41 +export const supportsClientAPIs = true;
42 +
43 +export const supportsRequestStorage = false;
44 +export const requestStorage: AsyncLocalStorage<Request | void> = (null: any);
45 +
46 +export const bindToConsole = $$$config.bindToConsole;
47 +
48 +export const resetResumableState = $$$config.resetResumableState;
49 +export const completeResumableState = $$$config.completeResumableState;
50 +export const getChildFormatContext = $$$config.getChildFormatContext;
51 +export const getSuspenseFallbackFormatContext =
52 + $$$config.getSuspenseFallbackFormatContext;
53 +export const getSuspenseContentFormatContext =
54 + $$$config.getSuspenseContentFormatContext;
55 +export const getViewTransitionFormatContext =
56 + $$$config.getViewTransitionFormatContext;
57 +export const makeId = $$$config.makeId;
58 +export const pushTextInstance = $$$config.pushTextInstance;
59 +export const pushStartInstance = $$$config.pushStartInstance;
60 +export const pushEndInstance = $$$config.pushEndInstance;
61 +export const pushSegmentFinale = $$$config.pushSegmentFinale;
62 +export const pushFormStateMarkerIsMatching =
63 + $$$config.pushFormStateMarkerIsMatching;
64 +export const pushFormStateMarkerIsNotMatching =
65 + $$$config.pushFormStateMarkerIsNotMatching;
66 +export const writeCompletedRoot = $$$config.writeCompletedRoot;
67 +export const writePlaceholder = $$$config.writePlaceholder;
68 +export const pushStartActivityBoundary = $$$config.pushStartActivityBoundary;
69 +export const pushEndActivityBoundary = $$$config.pushEndActivityBoundary;
70 +export const writeStartCompletedSuspenseBoundary =
71 + $$$config.writeStartCompletedSuspenseBoundary;
72 +export const writeStartPendingSuspenseBoundary =
73 + $$$config.writeStartPendingSuspenseBoundary;
74 +export const writeStartClientRenderedSuspenseBoundary =
75 + $$$config.writeStartClientRenderedSuspenseBoundary;
76 +export const writeEndCompletedSuspenseBoundary =
77 + $$$config.writeEndCompletedSuspenseBoundary;
78 +export const writeEndPendingSuspenseBoundary =
79 + $$$config.writeEndPendingSuspenseBoundary;
80 +export const writeEndClientRenderedSuspenseBoundary =
81 + $$$config.writeEndClientRenderedSuspenseBoundary;
82 +export const writeStartSegment = $$$config.writeStartSegment;
83 +export const writeEndSegment = $$$config.writeEndSegment;
84 +export const writeCompletedSegmentInstruction =
85 + $$$config.writeCompletedSegmentInstruction;
86 +export const writeCompletedBoundaryInstruction =
87 + $$$config.writeCompletedBoundaryInstruction;
88 +export const writeClientRenderBoundaryInstruction =
89 + $$$config.writeClientRenderBoundaryInstruction;
90 +export const NotPendingTransition = $$$config.NotPendingTransition;
91 +export const createPreambleState = $$$config.createPreambleState;
92 +export const canHavePreamble = $$$config.canHavePreamble;
93 +export const isPreambleContext = $$$config.isPreambleContext;
94 +export const isPreambleReady = $$$config.isPreambleReady;
95 +export const hoistPreambleState = $$$config.hoistPreambleState;
96 +
97 +// -------------------------
98 +// Resources
99 +// -------------------------
100 +export const writePreambleStart = $$$config.writePreambleStart;
101 +export const writePreambleEnd = $$$config.writePreambleEnd;
102 +export const writeHoistables = $$$config.writeHoistables;
103 +export const writeHoistablesForBoundary = $$$config.writeHoistablesForBoundary;
104 +export const writePostamble = $$$config.writePostamble;
105 +export const hoistHoistables = $$$config.hoistHoistables;
106 +export const createHoistableState = $$$config.createHoistableState;
107 +export const hasSuspenseyContent = $$$config.hasSuspenseyContent;
108 +export const emitEarlyPreloads = $$$config.emitEarlyPreloads;
packages/react-server/src/forks/ReactFlightServerConfig.noop.js new
+47
@@ -0,0 +1,47 @@
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 +import type {Request} from 'react-server/src/ReactFlightServer';
11 +import type {ReactComponentInfo} from 'shared/ReactTypes';
12 +
13 +export * from '../ReactFlightServerConfigBundlerCustom';
14 +
15 +export * from '../ReactFlightServerConfigDebugNoop';
16 +
17 +export * from '../ReactFlightStackConfigV8';
18 +export * from '../ReactServerConsoleConfigPlain';
19 +
20 +export type Hints = null;
21 +export type HintCode = string;
22 +export type HintModel<T: HintCode> = null; // eslint-disable-line no-unused-vars
23 +
24 +export const supportsRequestStorage = false;
25 +export const requestStorage: AsyncLocalStorage<Request | void> = (null: any);
26 +
27 +export const supportsComponentStorage = false;
28 +export const componentStorage: AsyncLocalStorage<ReactComponentInfo | void> =
29 + (null: any);
30 +
31 +export function createHints(): Hints {
32 + return null;
33 +}
34 +
35 +export type FormatContext = null;
36 +
37 +export function createRootFormatContext(): FormatContext {
38 + return null;
39 +}
40 +
41 +export function getChildFormatContext(
42 + parentContext: FormatContext,
43 + type: string,
44 + props: Object,
45 +): FormatContext {
46 + return parentContext;
47 +}
packages/react-server/src/forks/ReactServerStreamConfig.noop.js new
+48
@@ -0,0 +1,48 @@
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 +// This is a host config that's used for the `react-server` package on npm.
11 +// It is only used by third-party renderers.
12 +//
13 +// Its API lets you pass the host config as an argument.
14 +// However, inside the `react-server` we treat host config as a module.
15 +// This file is a shim between two worlds.
16 +//
17 +// It works because the `react-server` bundle is wrapped in something like:
18 +//
19 +// module.exports = function ($$$config) {
20 +// /* renderer code */
21 +// }
22 +//
23 +// So `$$$config` looks like a global variable, but it's
24 +// really an argument to a top-level wrapping function.
25 +
26 +declare const $$$config: $FlowFixMe;
27 +export opaque type Destination = mixed;
28 +
29 +export opaque type PrecomputedChunk = mixed;
30 +export opaque type Chunk = mixed;
31 +export opaque type BinaryChunk = mixed;
32 +
33 +export const scheduleWork = $$$config.scheduleWork;
34 +export const scheduleMicrotask = $$$config.scheduleMicrotask;
35 +export const beginWriting = $$$config.beginWriting;
36 +export const writeChunk = $$$config.writeChunk;
37 +export const writeChunkAndReturn = $$$config.writeChunkAndReturn;
38 +export const completeWriting = $$$config.completeWriting;
39 +export const flushBuffered = $$$config.flushBuffered;
40 +export const close = $$$config.close;
41 +export const closeWithError = $$$config.closeWithError;
42 +export const stringToChunk = $$$config.stringToChunk;
43 +export const stringToPrecomputedChunk = $$$config.stringToPrecomputedChunk;
44 +export const typedArrayToBinaryChunk = $$$config.typedArrayToBinaryChunk;
45 +export const byteLengthOfChunk = $$$config.byteLengthOfChunk;
46 +export const byteLengthOfBinaryChunk = $$$config.byteLengthOfBinaryChunk;
47 +export const createFastHash = $$$config.createFastHash;
48 +export const readAsDataURL = $$$config.readAsDataURL;
scripts/flow/config/flowconfig
-3
@@ -15,9 +15,6 @@
15 .*/__tests__/.*
16
17
18 -# TODO: noop should get its own inlinedHostConfig entry
19 -.*/packages/react-noop-renderer/.*
20 -
18 %REACT_RENDERER_FLOW_IGNORES%
19
20 [libs]
scripts/jest/setupHostConfigs.js
+6
@@ -248,3 +248,9 @@ jest.mock('shared/ReactDOMSharedInternals', () =>
248 );
249
250 jest.mock('scheduler', () => jest.requireActual('scheduler/unstable_mock'));
251 +
252 +if (global.__PERSISTENT__) {
253 + jest.mock('react-noop-renderer', () =>
254 + jest.requireActual('react-noop-renderer/persistent')
255 + );
256 +}
scripts/jest/setupTests.persistent.js
-4
@@ -1,7 +1,3 @@
1 'use strict';
2
3 -jest.mock('react-noop-renderer', () =>
4 - jest.requireActual('react-noop-renderer/persistent')
5 -);
6 -
3 global.__PERSISTENT__ = true;
scripts/jest/setupTests.xplat.js
-4
@@ -28,9 +28,5 @@ jest.mock('shared/ReactFeatureFlags', () => {
28 return actual;
29 });
30
31 -jest.mock('react-noop-renderer', () =>
32 - jest.requireActual('react-noop-renderer/persistent')
33 -);
34 -
31 global.__PERSISTENT__ = true;
32 global.__XPLAT__ = true;
scripts/shared/inlinedHostConfigs.js
+19
@@ -661,6 +661,25 @@ module.exports = [
661 isFlowTyped: false, // TODO: type it.
662 isServerSupported: false,
663 },
664 + {
665 + shortName: 'noop',
666 + entryPoints: [
667 + 'react-noop-renderer',
668 + 'react-noop-renderer/persistent',
669 + 'react-noop-renderer/server',
670 + 'react-noop-renderer/flight-server',
671 + 'react-noop-renderer/flight-client',
672 + ],
673 + paths: [
674 + 'react-noop-renderer',
675 + 'react-client/flight',
676 + 'react-server/flight',
677 + 'react-server/src/ReactFlightServerConfigDebugNoop.js',
678 + ],
679 + isFlowTyped: true,
680 + isServerSupported: true,
681 + isFlightSupported: true,
682 + },
683 {
684 shortName: 'custom',
685 entryPoints: [