Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions packages/react-client/src/ReactFlightReplyClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ function escapeStringValue(value: string): string {

export function processReply(
root: ReactServerValue,
formFieldPrefix: string,
resolve: (string | FormData) => void,
reject: (error: mixed) => void,
): void {
Expand Down Expand Up @@ -171,7 +172,7 @@ export function processReply(
// $FlowFixMe[incompatible-type] We know it's not null because we assigned it above.
const data: FormData = formData;
// eslint-disable-next-line react-internal/safe-string-coercion
data.append('' + promiseId, partJSON);
data.append(formFieldPrefix + promiseId, partJSON);
pendingParts--;
if (pendingParts === 0) {
resolve(data);
Expand Down Expand Up @@ -268,7 +269,7 @@ export function processReply(
// The reference to this function came from the same client so we can pass it back.
const refId = nextPartId++;
// eslint-disable-next-line react-internal/safe-string-coercion
formData.set('' + refId, metaDataJSON);
formData.set(formFieldPrefix + refId, metaDataJSON);
return serializeServerReferenceID(refId);
}
throw new Error(
Expand Down Expand Up @@ -308,7 +309,7 @@ export function processReply(
resolve(json);
} else {
// Otherwise, we use FormData to let us stream in the result.
formData.set('0', json);
formData.set(formFieldPrefix + '0', json);
if (pendingParts === 0) {
// $FlowFixMe[incompatible-call] this has already been refined.
resolve(formData);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ function encodeReply(
string | URLSearchParams | FormData,
> /* We don't use URLSearchParams yet but maybe */ {
return new Promise((resolve, reject) => {
processReply(value, resolve, reject);
processReply(value, '', resolve, reject);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ import {
import {
createResponse,
close,
resolveField,
resolveFile,
getRoot,
} from 'react-server/src/ReactFlightReplyServer';

Expand Down Expand Up @@ -79,20 +77,12 @@ function decodeReply<T>(
body: string | FormData,
webpackMap: ServerManifest,
): Thenable<T> {
const response = createResponse(webpackMap);
if (typeof body === 'string') {
resolveField(response, 0, body);
} else {
// $FlowFixMe[prop-missing] Flow doesn't know that forEach exists.
body.forEach((value: string | File, key: string) => {
const id = +key;
if (typeof value === 'string') {
resolveField(response, id, value);
} else {
resolveFile(response, id, value);
}
});
const form = new FormData();
form.append('0', body);
body = form;
}
const response = createResponse(webpackMap, '', body);
close(response);
return getRoot(response);
}
Expand Down
18 changes: 4 additions & 14 deletions packages/react-server-dom-webpack/src/ReactFlightDOMServerEdge.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ import {
import {
createResponse,
close,
resolveField,
resolveFile,
getRoot,
} from 'react-server/src/ReactFlightReplyServer';

Expand Down Expand Up @@ -79,20 +77,12 @@ function decodeReply<T>(
body: string | FormData,
webpackMap: ServerManifest,
): Thenable<T> {
const response = createResponse(webpackMap);
if (typeof body === 'string') {
resolveField(response, 0, body);
} else {
// $FlowFixMe[prop-missing] Flow doesn't know that forEach exists.
body.forEach((value: string | File, key: string) => {
const id = +key;
if (typeof value === 'string') {
resolveField(response, id, value);
} else {
resolveFile(response, id, value);
}
});
const form = new FormData();
form.append('0', body);
body = form;
}
const response = createResponse(webpackMap, '', body);
close(response);
return getRoot(response);
}
Expand Down
25 changes: 7 additions & 18 deletions packages/react-server-dom-webpack/src/ReactFlightDOMServerNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import {
reportGlobalError,
close,
resolveField,
resolveFile,
resolveFileInfo,
resolveFileChunk,
resolveFileComplete,
Expand Down Expand Up @@ -88,10 +87,9 @@ function decodeReplyFromBusboy<T>(
busboyStream: Busboy,
webpackMap: ServerManifest,
): Thenable<T> {
const response = createResponse(webpackMap);
const response = createResponse(webpackMap, '');
busboyStream.on('field', (name, value) => {
const id = +name;
resolveField(response, id, value);
resolveField(response, name, value);
});
busboyStream.on('file', (name, value, {filename, encoding, mimeType}) => {
if (encoding.toLowerCase() === 'base64') {
Expand All @@ -101,8 +99,7 @@ function decodeReplyFromBusboy<T>(
'the wrong assumption, we can easily fix it.',
);
}
const id = +name;
const file = resolveFileInfo(response, id, filename, mimeType);
const file = resolveFileInfo(response, name, filename, mimeType);
value.on('data', chunk => {
resolveFileChunk(response, file, chunk);
});
Expand All @@ -123,20 +120,12 @@ function decodeReply<T>(
body: string | FormData,
webpackMap: ServerManifest,
): Thenable<T> {
const response = createResponse(webpackMap);
if (typeof body === 'string') {
resolveField(response, 0, body);
} else {
// $FlowFixMe[prop-missing] Flow doesn't know that forEach exists.
body.forEach((value: string | File, key: string) => {
const id = +key;
if (typeof value === 'string') {
resolveField(response, id, value);
} else {
resolveFile(response, id, value);
}
});
const form = new FormData();
form.append('0', body);
body = form;
}
const response = createResponse(webpackMap, '', body);
close(response);
return getRoot(response);
}
Expand Down
47 changes: 35 additions & 12 deletions packages/react-server/src/ReactFlightReplyServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ Chunk.prototype.then = function <T>(

export type Response = {
_bundlerConfig: ServerManifest,
_prefix: string,
_formData: FormData,
_chunks: Map<number, SomeChunk<any>>,
_fromJSON: (key: string, value: JSONValue) => any,
};
Expand Down Expand Up @@ -309,7 +311,17 @@ function getChunk(response: Response, id: number): SomeChunk<any> {
const chunks = response._chunks;
let chunk = chunks.get(id);
if (!chunk) {
chunk = createPendingChunk(response);
const prefix = response._prefix;
const key = prefix + id;
// Check if we have this field in the backing store already.
const backingEntry = response._formData.get(key);
if (backingEntry != null) {
// We assume that this is a string entry for now.
chunk = createResolvedModelChunk(response, (backingEntry: any));
} else {
// We're still waiting on this entry to stream in.
chunk = createPendingChunk(response);
}
chunks.set(id, chunk);
}
return chunk;
Expand Down Expand Up @@ -452,10 +464,16 @@ function parseModelString(
return value;
}

export function createResponse(bundlerConfig: ServerManifest): Response {
export function createResponse(
bundlerConfig: ServerManifest,
formFieldPrefix: string,
backingFormData?: FormData = new FormData(),
): Response {
const chunks: Map<number, SomeChunk<any>> = new Map();
const response: Response = {
_bundlerConfig: bundlerConfig,
_prefix: formFieldPrefix,
_formData: backingFormData,
_chunks: chunks,
_fromJSON: function (this: any, key: string, value: JSONValue) {
if (typeof value === 'string') {
Expand All @@ -470,27 +488,32 @@ export function createResponse(bundlerConfig: ServerManifest): Response {

export function resolveField(
response: Response,
id: number,
model: string,
key: string,
value: string,
): void {
const chunks = response._chunks;
const chunk = chunks.get(id);
if (!chunk) {
chunks.set(id, createResolvedModelChunk(response, model));
} else {
resolveModelChunk(chunk, model);
// Add this field to the backing store.
response._formData.append(key, value);
const prefix = response._prefix;
if (key.startsWith(prefix)) {
const chunks = response._chunks;
const id = +key.substr(prefix.length);
const chunk = chunks.get(id);
if (chunk) {
// We were waiting on this key so now we can resolve it.
resolveModelChunk(chunk, value);
}
}
}

export function resolveFile(response: Response, id: number, file: File): void {
export function resolveFile(response: Response, key: string, file: File): void {
throw new Error('Not implemented.');
}

export opaque type FileHandle = {};

export function resolveFileInfo(
response: Response,
id: number,
key: string,
filename: string,
mime: string,
): FileHandle {
Expand Down