mirror of
https://github.com/hanzoai/react.git
synced 2026-09-24 17:02:27 +00:00
* use return from onError * export getSuspenseInstanceFallbackError * stringToChunk * return string from onError in downstream type signatures * 1 more type * support encoding errors in html stream and escape user input This commit adds another way to get errors to the suspense instance by encoding them as dataset properties of a template element at the head of the boundary. Previously if there was an error before the boundary flushed there was no way to stream the error to the client because there would never be a client render instruction. Additionally the error is sent in 3 parts 1) error hash - this is always sent (dev or prod) if one is provided 2) error message - Dev only 3) error component stack - Dev only, this now captures the stack at the point of error Another item addressed in this commit is the escaping of potentially unsafe data. all error components are escaped as test for browers when written into the html and as javascript strings when written into a client render instruction. * nits Co-authored-by: Marco Salazar <[email protected]>
103 lines
2.7 KiB
JavaScript
103 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 {Writable} from 'stream';
|
|
|
|
import ReactVersion from 'shared/ReactVersion';
|
|
|
|
import {
|
|
createRequest,
|
|
startWork,
|
|
startFlowing,
|
|
abort,
|
|
} from 'react-server/src/ReactFizzServer';
|
|
|
|
import {
|
|
createResponseState,
|
|
createRootFormatContext,
|
|
} from './ReactDOMServerFormatConfig';
|
|
|
|
function createDrainHandler(destination, request) {
|
|
return () => startFlowing(request, destination);
|
|
}
|
|
|
|
function createAbortHandler(request) {
|
|
return () => abort(request);
|
|
}
|
|
|
|
type Options = {|
|
|
identifierPrefix?: string,
|
|
namespaceURI?: string,
|
|
nonce?: string,
|
|
bootstrapScriptContent?: string,
|
|
bootstrapScripts?: Array<string>,
|
|
bootstrapModules?: Array<string>,
|
|
progressiveChunkSize?: number,
|
|
onShellReady?: () => void,
|
|
onShellError?: (error: mixed) => void,
|
|
onAllReady?: () => void,
|
|
onError?: (error: mixed) => ?string,
|
|
|};
|
|
|
|
type PipeableStream = {|
|
|
// Cancel any pending I/O and put anything remaining into
|
|
// client rendered mode.
|
|
abort(): void,
|
|
pipe<T: Writable>(destination: T): T,
|
|
|};
|
|
|
|
function createRequestImpl(children: ReactNodeList, options: void | Options) {
|
|
return createRequest(
|
|
children,
|
|
createResponseState(
|
|
options ? options.identifierPrefix : undefined,
|
|
options ? options.nonce : undefined,
|
|
options ? options.bootstrapScriptContent : undefined,
|
|
options ? options.bootstrapScripts : undefined,
|
|
options ? options.bootstrapModules : undefined,
|
|
),
|
|
createRootFormatContext(options ? options.namespaceURI : undefined),
|
|
options ? options.progressiveChunkSize : undefined,
|
|
options ? options.onError : undefined,
|
|
options ? options.onAllReady : undefined,
|
|
options ? options.onShellReady : undefined,
|
|
options ? options.onShellError : undefined,
|
|
undefined,
|
|
);
|
|
}
|
|
|
|
function renderToPipeableStream(
|
|
children: ReactNodeList,
|
|
options?: Options,
|
|
): PipeableStream {
|
|
const request = createRequestImpl(children, options);
|
|
let hasStartedFlowing = false;
|
|
startWork(request);
|
|
return {
|
|
pipe<T: Writable>(destination: T): T {
|
|
if (hasStartedFlowing) {
|
|
throw new Error(
|
|
'React currently only supports piping to one writable stream.',
|
|
);
|
|
}
|
|
hasStartedFlowing = true;
|
|
startFlowing(request, destination);
|
|
destination.on('drain', createDrainHandler(destination, request));
|
|
destination.on('close', createAbortHandler(request));
|
|
return destination;
|
|
},
|
|
abort() {
|
|
abort(request);
|
|
},
|
|
};
|
|
}
|
|
|
|
export {renderToPipeableStream, ReactVersion as version};
|