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 {ReactNodeList} from 'shared/ReactTypes';
    
  11. 
    
  12. import type {Request} from 'react-server/src/ReactFizzServer';
    
  13. 
    
  14. import {
    
  15.   createRequest,
    
  16.   startWork,
    
  17.   startFlowing,
    
  18.   abort,
    
  19. } from 'react-server/src/ReactFizzServer';
    
  20. 
    
  21. import {
    
  22.   createResumableState,
    
  23.   createRenderState,
    
  24.   createRootFormatContext,
    
  25. } from 'react-dom-bindings/src/server/ReactFizzConfigDOMLegacy';
    
  26. 
    
  27. import {Readable} from 'stream';
    
  28. 
    
  29. type ServerOptions = {
    
  30.   identifierPrefix?: string,
    
  31. };
    
  32. 
    
  33. class ReactMarkupReadableStream extends Readable {
    
  34.   request: Request;
    
  35.   startedFlowing: boolean;
    
  36.   constructor() {
    
  37.     // Calls the stream.Readable(options) constructor. Consider exposing built-in
    
  38.     // features like highWaterMark in the future.
    
  39.     super({});
    
  40.     this.request = (null: any);
    
  41.     this.startedFlowing = false;
    
  42.   }
    
  43. 
    
  44.   // $FlowFixMe[missing-local-annot]
    
  45.   _destroy(err, callback) {
    
  46.     abort(this.request);
    
  47.     callback(err);
    
  48.   }
    
  49. 
    
  50.   // $FlowFixMe[missing-local-annot]
    
  51.   _read(size) {
    
  52.     if (this.startedFlowing) {
    
  53.       startFlowing(this.request, this);
    
  54.     }
    
  55.   }
    
  56. }
    
  57. 
    
  58. function onError() {
    
  59.   // Non-fatal errors are ignored.
    
  60. }
    
  61. 
    
  62. function renderToNodeStreamImpl(
    
  63.   children: ReactNodeList,
    
  64.   options: void | ServerOptions,
    
  65.   generateStaticMarkup: boolean,
    
  66. ): Readable {
    
  67.   function onAllReady() {
    
  68.     // We wait until everything has loaded before starting to write.
    
  69.     // That way we only end up with fully resolved HTML even if we suspend.
    
  70.     destination.startedFlowing = true;
    
  71.     startFlowing(request, destination);
    
  72.   }
    
  73.   const destination = new ReactMarkupReadableStream();
    
  74.   const resumableState = createResumableState(
    
  75.     options ? options.identifierPrefix : undefined,
    
  76.     undefined,
    
  77.   );
    
  78.   const request = createRequest(
    
  79.     children,
    
  80.     resumableState,
    
  81.     createRenderState(resumableState, false),
    
  82.     createRootFormatContext(),
    
  83.     Infinity,
    
  84.     onError,
    
  85.     onAllReady,
    
  86.     undefined,
    
  87.     undefined,
    
  88.     undefined,
    
  89.   );
    
  90.   destination.request = request;
    
  91.   startWork(request);
    
  92.   return destination;
    
  93. }
    
  94. 
    
  95. function renderToNodeStream(
    
  96.   children: ReactNodeList,
    
  97.   options?: ServerOptions,
    
  98. ): Readable {
    
  99.   if (__DEV__) {
    
  100.     console.error(
    
  101.       'renderToNodeStream is deprecated. Use renderToPipeableStream instead.',
    
  102.     );
    
  103.   }
    
  104.   return renderToNodeStreamImpl(children, options, false);
    
  105. }
    
  106. 
    
  107. function renderToStaticNodeStream(
    
  108.   children: ReactNodeList,
    
  109.   options?: ServerOptions,
    
  110. ): Readable {
    
  111.   return renderToNodeStreamImpl(children, options, true);
    
  112. }
    
  113. 
    
  114. export {renderToNodeStream, renderToStaticNodeStream};