mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
cb1e7b1c6c
* Move onCompleteAll to .allReady Promise The onCompleteAll callback can sometimes resolve before the promise that returns the stream which is tough to coordinate. A more idiomatic API for a one shot event is a Promise. That way the way you render for SEO or SSG is: const stream = await renderToReadableStream(...); await stream.readyAll; respondWith(stream); Ideally this should be a sub-class of ReadableStream but we don't yet compile these to ES6 and they'd had to be to native class to subclass a native stream. I have other ideas for overriding the .tee() method in a subclass anyway. So this is inline with that strategy. * Reject the Promise on fatal errors
119 lines
2.7 KiB
JavaScript
119 lines
2.7 KiB
JavaScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @flow
|
|
*/
|
|
|
|
import type {ReactNodeList} from 'shared/ReactTypes';
|
|
|
|
import type {Request} from 'react-server/src/ReactFizzServer';
|
|
|
|
import {
|
|
createRequest,
|
|
startWork,
|
|
startFlowing,
|
|
abort,
|
|
} from 'react-server/src/ReactFizzServer';
|
|
|
|
import {
|
|
createResponseState,
|
|
createRootFormatContext,
|
|
} from './ReactDOMServerLegacyFormatConfig';
|
|
|
|
import {
|
|
version,
|
|
renderToString,
|
|
renderToStaticMarkup,
|
|
} from './ReactDOMLegacyServerBrowser';
|
|
|
|
import {Readable} from 'stream';
|
|
|
|
type ServerOptions = {
|
|
identifierPrefix?: string,
|
|
};
|
|
|
|
class ReactMarkupReadableStream extends Readable {
|
|
request: Request;
|
|
startedFlowing: boolean;
|
|
constructor() {
|
|
// Calls the stream.Readable(options) constructor. Consider exposing built-in
|
|
// features like highWaterMark in the future.
|
|
super({});
|
|
this.request = (null: any);
|
|
this.startedFlowing = false;
|
|
}
|
|
|
|
_destroy(err, callback) {
|
|
abort(this.request);
|
|
// $FlowFixMe: The type definition for the callback should allow undefined and null.
|
|
callback(err);
|
|
}
|
|
|
|
_read(size) {
|
|
if (this.startedFlowing) {
|
|
startFlowing(this.request, this);
|
|
}
|
|
}
|
|
}
|
|
|
|
function onError() {
|
|
// Non-fatal errors are ignored.
|
|
}
|
|
|
|
function renderToNodeStreamImpl(
|
|
children: ReactNodeList,
|
|
options: void | ServerOptions,
|
|
generateStaticMarkup: boolean,
|
|
): Readable {
|
|
function onCompleteAll() {
|
|
// We wait until everything has loaded before starting to write.
|
|
// That way we only end up with fully resolved HTML even if we suspend.
|
|
destination.startedFlowing = true;
|
|
startFlowing(request, destination);
|
|
}
|
|
const destination = new ReactMarkupReadableStream();
|
|
const request = createRequest(
|
|
children,
|
|
createResponseState(false, options ? options.identifierPrefix : undefined),
|
|
createRootFormatContext(),
|
|
Infinity,
|
|
onError,
|
|
onCompleteAll,
|
|
undefined,
|
|
undefined,
|
|
);
|
|
destination.request = request;
|
|
startWork(request);
|
|
return destination;
|
|
}
|
|
|
|
function renderToNodeStream(
|
|
children: ReactNodeList,
|
|
options?: ServerOptions,
|
|
): Readable {
|
|
if (__DEV__) {
|
|
console.error(
|
|
'renderToNodeStream is deprecated. Use renderToPipeableStream instead.',
|
|
);
|
|
}
|
|
return renderToNodeStreamImpl(children, options, false);
|
|
}
|
|
|
|
function renderToStaticNodeStream(
|
|
children: ReactNodeList,
|
|
options?: ServerOptions,
|
|
): Readable {
|
|
return renderToNodeStreamImpl(children, options, true);
|
|
}
|
|
|
|
export {
|
|
renderToString,
|
|
renderToStaticMarkup,
|
|
renderToNodeStream,
|
|
renderToStaticNodeStream,
|
|
version,
|
|
};
|