Skip to content

Commit 525bbf1

Browse files
committed
Use prefixed form data backing store for unresolved values
1 parent b600620 commit 525bbf1

File tree

6 files changed

+55
-62
lines changed

6 files changed

+55
-62
lines changed

packages/react-client/src/ReactFlightReplyClient.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ function escapeStringValue(value: string): string {
112112

113113
export function processReply(
114114
root: ReactServerValue,
115+
formFieldPrefix: string,
115116
resolve: (string | FormData) => void,
116117
reject: (error: mixed) => void,
117118
): void {
@@ -171,7 +172,7 @@ export function processReply(
171172
// $FlowFixMe[incompatible-type] We know it's not null because we assigned it above.
172173
const data: FormData = formData;
173174
// eslint-disable-next-line react-internal/safe-string-coercion
174-
data.append('' + promiseId, partJSON);
175+
data.append(formFieldPrefix + promiseId, partJSON);
175176
pendingParts--;
176177
if (pendingParts === 0) {
177178
resolve(data);
@@ -268,7 +269,7 @@ export function processReply(
268269
// The reference to this function came from the same client so we can pass it back.
269270
const refId = nextPartId++;
270271
// eslint-disable-next-line react-internal/safe-string-coercion
271-
formData.set('' + refId, metaDataJSON);
272+
formData.set(formFieldPrefix + refId, metaDataJSON);
272273
return serializeServerReferenceID(refId);
273274
}
274275
throw new Error(
@@ -308,7 +309,7 @@ export function processReply(
308309
resolve(json);
309310
} else {
310311
// Otherwise, we use FormData to let us stream in the result.
311-
formData.set('0', json);
312+
formData.set(formFieldPrefix + '0', json);
312313
if (pendingParts === 0) {
313314
// $FlowFixMe[incompatible-call] this has already been refined.
314315
resolve(formData);

packages/react-server-dom-webpack/src/ReactFlightDOMClientBrowser.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ function encodeReply(
124124
string | URLSearchParams | FormData,
125125
> /* We don't use URLSearchParams yet but maybe */ {
126126
return new Promise((resolve, reject) => {
127-
processReply(value, resolve, reject);
127+
processReply(value, '', resolve, reject);
128128
});
129129
}
130130

packages/react-server-dom-webpack/src/ReactFlightDOMServerBrowser.js

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ import {
2222
import {
2323
createResponse,
2424
close,
25-
resolveField,
26-
resolveFile,
2725
getRoot,
2826
} from 'react-server/src/ReactFlightReplyServer';
2927

@@ -79,20 +77,12 @@ function decodeReply<T>(
7977
body: string | FormData,
8078
webpackMap: ServerManifest,
8179
): Thenable<T> {
82-
const response = createResponse(webpackMap);
8380
if (typeof body === 'string') {
84-
resolveField(response, 0, body);
85-
} else {
86-
// $FlowFixMe[prop-missing] Flow doesn't know that forEach exists.
87-
body.forEach((value: string | File, key: string) => {
88-
const id = +key;
89-
if (typeof value === 'string') {
90-
resolveField(response, id, value);
91-
} else {
92-
resolveFile(response, id, value);
93-
}
94-
});
81+
const form = new FormData();
82+
form.append('0', body);
83+
body = form;
9584
}
85+
const response = createResponse(webpackMap, '', body);
9686
close(response);
9787
return getRoot(response);
9888
}

packages/react-server-dom-webpack/src/ReactFlightDOMServerEdge.js

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ import {
2222
import {
2323
createResponse,
2424
close,
25-
resolveField,
26-
resolveFile,
2725
getRoot,
2826
} from 'react-server/src/ReactFlightReplyServer';
2927

@@ -79,20 +77,12 @@ function decodeReply<T>(
7977
body: string | FormData,
8078
webpackMap: ServerManifest,
8179
): Thenable<T> {
82-
const response = createResponse(webpackMap);
8380
if (typeof body === 'string') {
84-
resolveField(response, 0, body);
85-
} else {
86-
// $FlowFixMe[prop-missing] Flow doesn't know that forEach exists.
87-
body.forEach((value: string | File, key: string) => {
88-
const id = +key;
89-
if (typeof value === 'string') {
90-
resolveField(response, id, value);
91-
} else {
92-
resolveFile(response, id, value);
93-
}
94-
});
81+
const form = new FormData();
82+
form.append('0', body);
83+
body = form;
9584
}
85+
const response = createResponse(webpackMap, '', body);
9686
close(response);
9787
return getRoot(response);
9888
}

packages/react-server-dom-webpack/src/ReactFlightDOMServerNode.js

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ import {
3030
reportGlobalError,
3131
close,
3232
resolveField,
33-
resolveFile,
3433
resolveFileInfo,
3534
resolveFileChunk,
3635
resolveFileComplete,
@@ -88,10 +87,9 @@ function decodeReplyFromBusboy<T>(
8887
busboyStream: Busboy,
8988
webpackMap: ServerManifest,
9089
): Thenable<T> {
91-
const response = createResponse(webpackMap);
90+
const response = createResponse(webpackMap, '');
9291
busboyStream.on('field', (name, value) => {
93-
const id = +name;
94-
resolveField(response, id, value);
92+
resolveField(response, name, value);
9593
});
9694
busboyStream.on('file', (name, value, {filename, encoding, mimeType}) => {
9795
if (encoding.toLowerCase() === 'base64') {
@@ -101,8 +99,7 @@ function decodeReplyFromBusboy<T>(
10199
'the wrong assumption, we can easily fix it.',
102100
);
103101
}
104-
const id = +name;
105-
const file = resolveFileInfo(response, id, filename, mimeType);
102+
const file = resolveFileInfo(response, name, filename, mimeType);
106103
value.on('data', chunk => {
107104
resolveFileChunk(response, file, chunk);
108105
});
@@ -123,20 +120,12 @@ function decodeReply<T>(
123120
body: string | FormData,
124121
webpackMap: ServerManifest,
125122
): Thenable<T> {
126-
const response = createResponse(webpackMap);
127123
if (typeof body === 'string') {
128-
resolveField(response, 0, body);
129-
} else {
130-
// $FlowFixMe[prop-missing] Flow doesn't know that forEach exists.
131-
body.forEach((value: string | File, key: string) => {
132-
const id = +key;
133-
if (typeof value === 'string') {
134-
resolveField(response, id, value);
135-
} else {
136-
resolveFile(response, id, value);
137-
}
138-
});
124+
const form = new FormData();
125+
form.append('0', body);
126+
body = form;
139127
}
128+
const response = createResponse(webpackMap, '', body);
140129
close(response);
141130
return getRoot(response);
142131
}

packages/react-server/src/ReactFlightReplyServer.js

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ Chunk.prototype.then = function <T>(
131131

132132
export type Response = {
133133
_bundlerConfig: ServerManifest,
134+
_prefix: string,
135+
_formData: FormData,
134136
_chunks: Map<number, SomeChunk<any>>,
135137
_fromJSON: (key: string, value: JSONValue) => any,
136138
};
@@ -309,7 +311,17 @@ function getChunk(response: Response, id: number): SomeChunk<any> {
309311
const chunks = response._chunks;
310312
let chunk = chunks.get(id);
311313
if (!chunk) {
312-
chunk = createPendingChunk(response);
314+
const prefix = response._prefix;
315+
const key = prefix + id;
316+
// Check if we have this field in the backing store already.
317+
const backingEntry = response._formData.get(key);
318+
if (backingEntry != null) {
319+
// We assume that this is a string entry for now.
320+
chunk = createResolvedModelChunk(response, (backingEntry: any));
321+
} else {
322+
// We're still waiting on this entry to stream in.
323+
chunk = createPendingChunk(response);
324+
}
313325
chunks.set(id, chunk);
314326
}
315327
return chunk;
@@ -452,10 +464,16 @@ function parseModelString(
452464
return value;
453465
}
454466

455-
export function createResponse(bundlerConfig: ServerManifest): Response {
467+
export function createResponse(
468+
bundlerConfig: ServerManifest,
469+
formFieldPrefix: string,
470+
backingFormData?: FormData = new FormData(),
471+
): Response {
456472
const chunks: Map<number, SomeChunk<any>> = new Map();
457473
const response: Response = {
458474
_bundlerConfig: bundlerConfig,
475+
_prefix: formFieldPrefix,
476+
_formData: backingFormData,
459477
_chunks: chunks,
460478
_fromJSON: function (this: any, key: string, value: JSONValue) {
461479
if (typeof value === 'string') {
@@ -470,27 +488,32 @@ export function createResponse(bundlerConfig: ServerManifest): Response {
470488

471489
export function resolveField(
472490
response: Response,
473-
id: number,
474-
model: string,
491+
key: string,
492+
value: string,
475493
): void {
476-
const chunks = response._chunks;
477-
const chunk = chunks.get(id);
478-
if (!chunk) {
479-
chunks.set(id, createResolvedModelChunk(response, model));
480-
} else {
481-
resolveModelChunk(chunk, model);
494+
// Add this field to the backing store.
495+
response._formData.append(key, value);
496+
const prefix = response._prefix;
497+
if (key.startsWith(prefix)) {
498+
const chunks = response._chunks;
499+
const id = +key.substr(prefix.length);
500+
const chunk = chunks.get(id);
501+
if (chunk) {
502+
// We were waiting on this key so now we can resolve it.
503+
resolveModelChunk(chunk, value);
504+
}
482505
}
483506
}
484507

485-
export function resolveFile(response: Response, id: number, file: File): void {
508+
export function resolveFile(response: Response, key: string, file: File): void {
486509
throw new Error('Not implemented.');
487510
}
488511

489512
export opaque type FileHandle = {};
490513

491514
export function resolveFileInfo(
492515
response: Response,
493-
id: number,
516+
key: string,
494517
filename: string,
495518
mime: string,
496519
): FileHandle {

0 commit comments

Comments
 (0)