Files
react/packages/react-server-dom-webpack/src/ReactFlightDOMServerEdge.js
T
Sebastian Markbåge fdc8c81e07 [Flight] Client and Server Reference Creation into Runtime (#27033)
We already did this for Server References on the Client so this brings
us parity with that. This gives us some more flexibility with changing
the runtime implementation without having to affect the loaders.

We can also do more in the runtime such as adding `.bind()` support to
Server References.

I also moved the CommonJS Proxy creation into the runtime helper from
the register so that it can be handled in one place.

This lets us remove the forks from Next.js since the loaders can be
simplified there to just use these helpers.

This PR doesn't change the protocol or shape of the objects. They're
still specific to each bundler but ideally we should probably move this
to shared helpers that can be used by multiple bundler implementations.
2023-07-07 11:09:45 -04:00

99 lines
2.5 KiB
JavaScript

/**
* Copyright (c) Meta Platforms, Inc. and 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 {ReactClientValue} from 'react-server/src/ReactFlightServer';
import type {ServerContextJSONValue, Thenable} from 'shared/ReactTypes';
import type {ClientManifest} from './ReactFlightServerConfigWebpackBundler';
import type {ServerManifest} from 'react-client/src/ReactFlightClientConfig';
import {
createRequest,
startWork,
startFlowing,
abort,
} from 'react-server/src/ReactFlightServer';
import {
createResponse,
close,
getRoot,
} from 'react-server/src/ReactFlightReplyServer';
import {decodeAction} from 'react-server/src/ReactFlightActionServer';
export {
registerServerReference,
registerClientReference,
createClientModuleProxy,
} from './ReactFlightWebpackReferences';
type Options = {
identifierPrefix?: string,
signal?: AbortSignal,
context?: Array<[string, ServerContextJSONValue]>,
onError?: (error: mixed) => void,
};
function renderToReadableStream(
model: ReactClientValue,
webpackMap: ClientManifest,
options?: Options,
): ReadableStream {
const request = createRequest(
model,
webpackMap,
options ? options.onError : undefined,
options ? options.context : undefined,
options ? options.identifierPrefix : undefined,
);
if (options && options.signal) {
const signal = options.signal;
if (signal.aborted) {
abort(request, (signal: any).reason);
} else {
const listener = () => {
abort(request, (signal: any).reason);
signal.removeEventListener('abort', listener);
};
signal.addEventListener('abort', listener);
}
}
const stream = new ReadableStream(
{
type: 'bytes',
start: (controller): ?Promise<void> => {
startWork(request);
},
pull: (controller): ?Promise<void> => {
startFlowing(request, controller);
},
cancel: (reason): ?Promise<void> => {},
},
// $FlowFixMe[prop-missing] size() methods are not allowed on byte streams.
{highWaterMark: 0},
);
return stream;
}
function decodeReply<T>(
body: string | FormData,
webpackMap: ServerManifest,
): Thenable<T> {
if (typeof body === 'string') {
const form = new FormData();
form.append('0', body);
body = form;
}
const response = createResponse(webpackMap, '', body);
close(response);
return getRoot(response);
}
export {renderToReadableStream, decodeReply, decodeAction};