Split writeChunk into void and return value (#23343)
This function was modeled after Node streams where write returns a boolean whether to keep writing or not. I think we should probably switch this up and read desired size explicitly in appropriate places. However, in the meantime, we don't have to return a value where we're not going to use it. So I split this so that we call writeChunkAndReturn if we're going to return the boolean. This should help with the compilation so that they can be inlined.
Sebastian Markbåge committed
Feb 23, 2022 at 11:35 UTC
40351575d3cfaef62426c889a90431c01fdeff0f
14 files changed
+130
-61
packages/react-dom/src/server/ReactDOMLegacyServerStreamConfig.js
+7
@@ -28,6 +28,13 @@ let prevWasCommentSegmenter = false;
28
export function writeChunk(
29
destination: Destination,
30
chunk: Chunk | PrecomputedChunk,
31
+): void {
32
+ writeChunkAndReturn(destination, chunk);
33
+}
34
+
35
+export function writeChunkAndReturn(
36
+ destination: Destination,
37
+ chunk: Chunk | PrecomputedChunk,
38
): boolean {
39
if (prevWasCommentSegmenter) {
40
prevWasCommentSegmenter = false;
packages/react-dom/src/server/ReactDOMServerFormatConfig.js
+32
-28
@@ -30,6 +30,7 @@ import type {
30
31
import {
32
writeChunk,
33
+ writeChunkAndReturn,
34
stringToChunk,
35
stringToPrecomputedChunk,
36
} from 'react-server/src/ReactServerStreamConfig';
@@ -1427,11 +1428,14 @@ export function writeCompletedRoot(
1428
responseState: ResponseState,
1429
): boolean {
1430
const bootstrapChunks = responseState.bootstrapChunks;
1430
- let result = true;
1431
- for (let i = 0; i < bootstrapChunks.length; i++) {
1432
- result = writeChunk(destination, bootstrapChunks[i]);
1431
+ let i = 0;
1432
+ for (; i < bootstrapChunks.length - 1; i++) {
1433
+ writeChunk(destination, bootstrapChunks[i]);
1434
}
1434
- return result;
1435
+ if (i < bootstrapChunks.length) {
1436
+ return writeChunkAndReturn(destination, bootstrapChunks[i]);
1437
+ }
1438
+ return true;
1439
}
1440
1441
// Structural Nodes
@@ -1450,7 +1454,7 @@ export function writePlaceholder(
1454
writeChunk(destination, responseState.placeholderPrefix);
1455
const formattedID = stringToChunk(id.toString(16));
1456
writeChunk(destination, formattedID);
1453
- return writeChunk(destination, placeholder2);
1457
+ return writeChunkAndReturn(destination, placeholder2);
1458
}
1459
1460
// Suspense boundaries are encoded as comments.
@@ -1480,7 +1484,7 @@ export function writeStartCompletedSuspenseBoundary(
1484
destination: Destination,
1485
responseState: ResponseState,
1486
): boolean {
1483
- return writeChunk(destination, startCompletedSuspenseBoundary);
1487
+ return writeChunkAndReturn(destination, startCompletedSuspenseBoundary);
1488
}
1489
export function writeStartPendingSuspenseBoundary(
1490
destination: Destination,
@@ -1496,31 +1500,31 @@ export function writeStartPendingSuspenseBoundary(
1500
}
1501
1502
writeChunk(destination, id);
1499
- return writeChunk(destination, startPendingSuspenseBoundary2);
1503
+ return writeChunkAndReturn(destination, startPendingSuspenseBoundary2);
1504
}
1505
export function writeStartClientRenderedSuspenseBoundary(
1506
destination: Destination,
1507
responseState: ResponseState,
1508
): boolean {
1505
- return writeChunk(destination, startClientRenderedSuspenseBoundary);
1509
+ return writeChunkAndReturn(destination, startClientRenderedSuspenseBoundary);
1510
}
1511
export function writeEndCompletedSuspenseBoundary(
1512
destination: Destination,
1513
responseState: ResponseState,
1514
): boolean {
1511
- return writeChunk(destination, endSuspenseBoundary);
1515
+ return writeChunkAndReturn(destination, endSuspenseBoundary);
1516
}
1517
export function writeEndPendingSuspenseBoundary(
1518
destination: Destination,
1519
responseState: ResponseState,
1520
): boolean {
1517
- return writeChunk(destination, endSuspenseBoundary);
1521
+ return writeChunkAndReturn(destination, endSuspenseBoundary);
1522
}
1523
export function writeEndClientRenderedSuspenseBoundary(
1524
destination: Destination,
1525
responseState: ResponseState,
1526
): boolean {
1523
- return writeChunk(destination, endSuspenseBoundary);
1527
+ return writeChunkAndReturn(destination, endSuspenseBoundary);
1528
}
1529
1530
const startSegmentHTML = stringToPrecomputedChunk('<div hidden id="');
@@ -1571,25 +1575,25 @@ export function writeStartSegment(
1575
writeChunk(destination, startSegmentHTML);
1576
writeChunk(destination, responseState.segmentPrefix);
1577
writeChunk(destination, stringToChunk(id.toString(16)));
1574
- return writeChunk(destination, startSegmentHTML2);
1578
+ return writeChunkAndReturn(destination, startSegmentHTML2);
1579
}
1580
case SVG_MODE: {
1581
writeChunk(destination, startSegmentSVG);
1582
writeChunk(destination, responseState.segmentPrefix);
1583
writeChunk(destination, stringToChunk(id.toString(16)));
1580
- return writeChunk(destination, startSegmentSVG2);
1584
+ return writeChunkAndReturn(destination, startSegmentSVG2);
1585
}
1586
case MATHML_MODE: {
1587
writeChunk(destination, startSegmentMathML);
1588
writeChunk(destination, responseState.segmentPrefix);
1589
writeChunk(destination, stringToChunk(id.toString(16)));
1586
- return writeChunk(destination, startSegmentMathML2);
1590
+ return writeChunkAndReturn(destination, startSegmentMathML2);
1591
}
1592
case HTML_TABLE_MODE: {
1593
writeChunk(destination, startSegmentTable);
1594
writeChunk(destination, responseState.segmentPrefix);
1595
writeChunk(destination, stringToChunk(id.toString(16)));
1592
- return writeChunk(destination, startSegmentTable2);
1596
+ return writeChunkAndReturn(destination, startSegmentTable2);
1597
}
1598
// TODO: For the rest of these, there will be extra wrapper nodes that never
1599
// get deleted from the document. We need to delete the table too as part
@@ -1599,19 +1603,19 @@ export function writeStartSegment(
1603
writeChunk(destination, startSegmentTableBody);
1604
writeChunk(destination, responseState.segmentPrefix);
1605
writeChunk(destination, stringToChunk(id.toString(16)));
1602
- return writeChunk(destination, startSegmentTableBody2);
1606
+ return writeChunkAndReturn(destination, startSegmentTableBody2);
1607
}
1608
case HTML_TABLE_ROW_MODE: {
1609
writeChunk(destination, startSegmentTableRow);
1610
writeChunk(destination, responseState.segmentPrefix);
1611
writeChunk(destination, stringToChunk(id.toString(16)));
1608
- return writeChunk(destination, startSegmentTableRow2);
1612
+ return writeChunkAndReturn(destination, startSegmentTableRow2);
1613
}
1614
case HTML_COLGROUP_MODE: {
1615
writeChunk(destination, startSegmentColGroup);
1616
writeChunk(destination, responseState.segmentPrefix);
1617
writeChunk(destination, stringToChunk(id.toString(16)));
1614
- return writeChunk(destination, startSegmentColGroup2);
1618
+ return writeChunkAndReturn(destination, startSegmentColGroup2);
1619
}
1620
default: {
1621
throw new Error('Unknown insertion mode. This is a bug in React.');
@@ -1625,25 +1629,25 @@ export function writeEndSegment(
1629
switch (formatContext.insertionMode) {
1630
case ROOT_HTML_MODE:
1631
case HTML_MODE: {
1628
- return writeChunk(destination, endSegmentHTML);
1632
+ return writeChunkAndReturn(destination, endSegmentHTML);
1633
}
1634
case SVG_MODE: {
1631
- return writeChunk(destination, endSegmentSVG);
1635
+ return writeChunkAndReturn(destination, endSegmentSVG);
1636
}
1637
case MATHML_MODE: {
1634
- return writeChunk(destination, endSegmentMathML);
1638
+ return writeChunkAndReturn(destination, endSegmentMathML);
1639
}
1640
case HTML_TABLE_MODE: {
1637
- return writeChunk(destination, endSegmentTable);
1641
+ return writeChunkAndReturn(destination, endSegmentTable);
1642
}
1643
case HTML_TABLE_BODY_MODE: {
1640
- return writeChunk(destination, endSegmentTableBody);
1644
+ return writeChunkAndReturn(destination, endSegmentTableBody);
1645
}
1646
case HTML_TABLE_ROW_MODE: {
1643
- return writeChunk(destination, endSegmentTableRow);
1647
+ return writeChunkAndReturn(destination, endSegmentTableRow);
1648
}
1649
case HTML_COLGROUP_MODE: {
1646
- return writeChunk(destination, endSegmentColGroup);
1650
+ return writeChunkAndReturn(destination, endSegmentColGroup);
1651
}
1652
default: {
1653
throw new Error('Unknown insertion mode. This is a bug in React.');
@@ -1790,7 +1794,7 @@ export function writeCompletedSegmentInstruction(
1794
writeChunk(destination, completeSegmentScript2);
1795
writeChunk(destination, responseState.placeholderPrefix);
1796
writeChunk(destination, formattedID);
1793
- return writeChunk(destination, completeSegmentScript3);
1797
+ return writeChunkAndReturn(destination, completeSegmentScript3);
1798
}
1799
1800
const completeBoundaryScript1Full = stringToPrecomputedChunk(
@@ -1827,7 +1831,7 @@ export function writeCompletedBoundaryInstruction(
1831
writeChunk(destination, completeBoundaryScript2);
1832
writeChunk(destination, responseState.segmentPrefix);
1833
writeChunk(destination, formattedContentID);
1830
- return writeChunk(destination, completeBoundaryScript3);
1834
+ return writeChunkAndReturn(destination, completeBoundaryScript3);
1835
}
1836
1837
const clientRenderScript1Full = stringToPrecomputedChunk(
@@ -1858,5 +1862,5 @@ export function writeClientRenderBoundaryInstruction(
1862
}
1863
1864
writeChunk(destination, boundaryID);
1861
- return writeChunk(destination, clientRenderScript2);
1865
+ return writeChunkAndReturn(destination, clientRenderScript2);
1866
}
packages/react-native-renderer/src/server/ReactNativeServerFormatConfig.js
+12
-11
@@ -17,6 +17,7 @@ import type {
17
18
import {
19
writeChunk,
20
+ writeChunkAndReturn,
21
stringToChunk,
22
stringToPrecomputedChunk,
23
} from 'react-server/src/ReactServerStreamConfig';
@@ -185,7 +186,7 @@ export function writePlaceholder(
186
id: number,
187
): boolean {
188
writeChunk(destination, PLACEHOLDER);
188
- return writeChunk(destination, formatID(id));
189
+ return writeChunkAndReturn(destination, formatID(id));
190
}
191
192
// Suspense boundaries are encoded as comments.
@@ -193,7 +194,7 @@ export function writeStartCompletedSuspenseBoundary(
194
destination: Destination,
195
responseState: ResponseState,
196
): boolean {
196
- return writeChunk(destination, SUSPENSE_COMPLETE);
197
+ return writeChunkAndReturn(destination, SUSPENSE_COMPLETE);
198
}
199
200
export function pushStartCompletedSuspenseBoundary(
@@ -208,19 +209,19 @@ export function writeStartPendingSuspenseBoundary(
209
id: SuspenseBoundaryID,
210
): boolean {
211
writeChunk(destination, SUSPENSE_PENDING);
211
- return writeChunk(destination, formatID(id));
212
+ return writeChunkAndReturn(destination, formatID(id));
213
}
214
export function writeStartClientRenderedSuspenseBoundary(
215
destination: Destination,
216
responseState: ResponseState,
217
): boolean {
217
- return writeChunk(destination, SUSPENSE_CLIENT_RENDER);
218
+ return writeChunkAndReturn(destination, SUSPENSE_CLIENT_RENDER);
219
}
220
export function writeEndCompletedSuspenseBoundary(
221
destination: Destination,
222
responseState: ResponseState,
223
): boolean {
223
- return writeChunk(destination, END);
224
+ return writeChunkAndReturn(destination, END);
225
}
226
export function pushEndCompletedSuspenseBoundary(
227
target: Array<Chunk | PrecomputedChunk>,
@@ -231,13 +232,13 @@ export function writeEndPendingSuspenseBoundary(
232
destination: Destination,
233
responseState: ResponseState,
234
): boolean {
234
- return writeChunk(destination, END);
235
+ return writeChunkAndReturn(destination, END);
236
}
237
export function writeEndClientRenderedSuspenseBoundary(
238
destination: Destination,
239
responseState: ResponseState,
240
): boolean {
240
- return writeChunk(destination, END);
241
+ return writeChunkAndReturn(destination, END);
242
}
243
244
export function writeStartSegment(
@@ -247,13 +248,13 @@ export function writeStartSegment(
248
id: number,
249
): boolean {
250
writeChunk(destination, SEGMENT);
250
- return writeChunk(destination, formatID(id));
251
+ return writeChunkAndReturn(destination, formatID(id));
252
}
253
export function writeEndSegment(
254
destination: Destination,
255
formatContext: FormatContext,
256
): boolean {
256
- return writeChunk(destination, END);
257
+ return writeChunkAndReturn(destination, END);
258
}
259
260
// Instruction Set
@@ -276,7 +277,7 @@ export function writeCompletedBoundaryInstruction(
277
): boolean {
278
writeChunk(destination, SUSPENSE_UPDATE_TO_COMPLETE);
279
writeChunk(destination, formatID(boundaryID));
279
- return writeChunk(destination, formatID(contentSegmentID));
280
+ return writeChunkAndReturn(destination, formatID(contentSegmentID));
281
}
282
283
export function writeClientRenderBoundaryInstruction(
@@ -285,5 +286,5 @@ export function writeClientRenderBoundaryInstruction(
286
boundaryID: SuspenseBoundaryID,
287
): boolean {
288
writeChunk(destination, SUSPENSE_UPDATE_TO_CLIENT_RENDER);
288
- return writeChunk(destination, formatID(boundaryID));
289
+ return writeChunkAndReturn(destination, formatID(boundaryID));
290
}
packages/react-noop-renderer/src/ReactNoopFlightServer.js
+4
@@ -30,6 +30,10 @@ const ReactNoopFlightServer = ReactFlightServer({
30
writeChunk(destination: Destination, chunk: string): void {
31
destination.push(chunk);
32
},
33
+ writeChunkAndReturn(destination: Destination, chunk: string): boolean {
34
+ destination.push(chunk);
35
+ return true;
36
+ },
37
completeWriting(destination: Destination): void {},
38
close(destination: Destination): void {},
39
closeWithError(destination: Destination, error: mixed): void {},
packages/react-noop-renderer/src/ReactNoopServer.js
+22
-14
@@ -53,26 +53,34 @@ type Destination = {
53
54
const POP = Buffer.from('/', 'utf8');
55
56
+function write(destination: Destination, buffer: Uint8Array): void {
57
+ const stack = destination.stack;
58
+ if (buffer === POP) {
59
+ stack.pop();
60
+ return;
61
+ }
62
+ // We assume one chunk is one instance.
63
+ const instance = JSON.parse(Buffer.from((buffer: any)).toString('utf8'));
64
+ if (stack.length === 0) {
65
+ destination.root = instance;
66
+ } else {
67
+ const parent = stack[stack.length - 1];
68
+ parent.children.push(instance);
69
+ }
70
+ stack.push(instance);
71
+}
72
+
73
const ReactNoopServer = ReactFizzServer({
74
scheduleWork(callback: () => void) {
75
callback();
76
},
77
beginWriting(destination: Destination): void {},
78
writeChunk(destination: Destination, buffer: Uint8Array): void {
62
- const stack = destination.stack;
63
- if (buffer === POP) {
64
- stack.pop();
65
- return;
66
- }
67
- // We assume one chunk is one instance.
68
- const instance = JSON.parse(Buffer.from((buffer: any)).toString('utf8'));
69
- if (stack.length === 0) {
70
- destination.root = instance;
71
- } else {
72
- const parent = stack[stack.length - 1];
73
- parent.children.push(instance);
74
- }
75
- stack.push(instance);
79
+ write(destination, buffer);
80
+ },
81
+ writeChunkAndReturn(destination: Destination, buffer: Uint8Array): boolean {
82
+ write(destination, buffer);
83
+ return true;
84
},
85
completeWriting(destination: Destination): void {},
86
close(destination: Destination): void {},
packages/react-server-dom-relay/src/ReactFlightDOMRelayServerHostConfig.js
+8
-1
@@ -141,7 +141,14 @@ export function flushBuffered(destination: Destination) {}
141
142
export function beginWriting(destination: Destination) {}
143
144
-export function writeChunk(destination: Destination, chunk: Chunk): boolean {
144
+export function writeChunk(destination: Destination, chunk: Chunk): void {
145
+ emitRow(destination, chunk);
146
+}
147
+
148
+export function writeChunkAndReturn(
149
+ destination: Destination,
150
+ chunk: Chunk,
151
+): boolean {
152
emitRow(destination, chunk);
153
return true;
154
}
packages/react-server-dom-relay/src/ReactServerStreamConfigFB.js
+7
@@ -28,6 +28,13 @@ export function beginWriting(destination: Destination) {}
28
export function writeChunk(
29
destination: Destination,
30
chunk: Chunk | PrecomputedChunk,
31
+): void {
32
+ destination.buffer += chunk;
33
+}
34
+
35
+export function writeChunkAndReturn(
36
+ destination: Destination,
37
+ chunk: Chunk | PrecomputedChunk,
38
): boolean {
39
destination.buffer += chunk;
40
return true;
packages/react-server-native-relay/src/ReactFlightNativeRelayServerHostConfig.js
+8
-1
@@ -138,7 +138,14 @@ export function flushBuffered(destination: Destination) {}
138
139
export function beginWriting(destination: Destination) {}
140
141
-export function writeChunk(destination: Destination, chunk: Chunk): boolean {
141
+export function writeChunk(destination: Destination, chunk: Chunk): void {
142
+ emitRow(destination, chunk);
143
+}
144
+
145
+export function writeChunkAndReturn(
146
+ destination: Destination,
147
+ chunk: Chunk,
148
+): boolean {
149
emitRow(destination, chunk);
150
return true;
151
}
packages/react-server/src/ReactFizzServer.js
+6
-2
@@ -31,6 +31,7 @@ import {
31
scheduleWork,
32
beginWriting,
33
writeChunk,
34
+ writeChunkAndReturn,
35
completeWriting,
36
flushBuffered,
37
close,
@@ -1615,8 +1616,11 @@ function flushSubtree(
1616
r = flushSegment(request, destination, nextChild);
1617
}
1618
// Finally just write all the remaining chunks
1618
- for (; chunkIdx < chunks.length; chunkIdx++) {
1619
- r = writeChunk(destination, chunks[chunkIdx]);
1619
+ for (; chunkIdx < chunks.length - 1; chunkIdx++) {
1620
+ writeChunk(destination, chunks[chunkIdx]);
1621
+ }
1622
+ if (chunkIdx < chunks.length) {
1623
+ r = writeChunkAndReturn(destination, chunks[chunkIdx]);
1624
}
1625
return r;
1626
}
packages/react-server/src/ReactFlightServer.js
+7
-4
@@ -20,7 +20,7 @@ import type {
20
import {
21
scheduleWork,
22
beginWriting,
23
- writeChunk,
23
+ writeChunkAndReturn,
24
completeWriting,
25
flushBuffered,
26
close,
@@ -732,7 +732,8 @@ function flushCompletedChunks(
732
for (; i < moduleChunks.length; i++) {
733
request.pendingChunks--;
734
const chunk = moduleChunks[i];
735
- if (!writeChunk(destination, chunk)) {
735
+ const keepWriting: boolean = writeChunkAndReturn(destination, chunk);
736
+ if (!keepWriting) {
737
request.destination = null;
738
i++;
739
break;
@@ -745,7 +746,8 @@ function flushCompletedChunks(
746
for (; i < jsonChunks.length; i++) {
747
request.pendingChunks--;
748
const chunk = jsonChunks[i];
748
- if (!writeChunk(destination, chunk)) {
749
+ const keepWriting: boolean = writeChunkAndReturn(destination, chunk);
750
+ if (!keepWriting) {
751
request.destination = null;
752
i++;
753
break;
@@ -760,7 +762,8 @@ function flushCompletedChunks(
762
for (; i < errorChunks.length; i++) {
763
request.pendingChunks--;
764
const chunk = errorChunks[i];
763
- if (!writeChunk(destination, chunk)) {
765
+ const keepWriting: boolean = writeChunkAndReturn(destination, chunk);
766
+ if (!keepWriting) {
767
request.destination = null;
768
i++;
769
break;
packages/react-server/src/ReactFlightServerConfigStream.js
+1
@@ -124,6 +124,7 @@ export {
124
flushBuffered,
125
beginWriting,
126
writeChunk,
127
+ writeChunkAndReturn,
128
completeWriting,
129
close,
130
closeWithError,
packages/react-server/src/ReactServerStreamConfigBrowser.js
+7
@@ -26,6 +26,13 @@ export function beginWriting(destination: Destination) {}
26
export function writeChunk(
27
destination: Destination,
28
chunk: PrecomputedChunk | Chunk,
29
+): void {
30
+ destination.enqueue(chunk);
31
+}
32
+
33
+export function writeChunkAndReturn(
34
+ destination: Destination,
35
+ chunk: PrecomputedChunk | Chunk,
36
): boolean {
37
destination.enqueue(chunk);
38
return destination.desiredSize > 0;
packages/react-server/src/ReactServerStreamConfigNode.js
+8
@@ -43,6 +43,14 @@ export function beginWriting(destination: Destination) {
43
export function writeChunk(
44
destination: Destination,
45
chunk: Chunk | PrecomputedChunk,
46
+): void {
47
+ const nodeBuffer = ((chunk: any): Buffer | string); // close enough
48
+ destination.write(nodeBuffer);
49
+}
50
+
51
+export function writeChunkAndReturn(
52
+ destination: Destination,
53
+ chunk: Chunk | PrecomputedChunk,
54
): boolean {
55
const nodeBuffer = ((chunk: any): Buffer | string); // close enough
56
return destination.write(nodeBuffer);
packages/react-server/src/forks/ReactServerStreamConfig.custom.js
+1
@@ -32,6 +32,7 @@ export opaque type Chunk = mixed; // eslint-disable-line no-undef
32
export const scheduleWork = $$$hostConfig.scheduleWork;
33
export const beginWriting = $$$hostConfig.beginWriting;
34
export const writeChunk = $$$hostConfig.writeChunk;
35
+export const writeChunkAndReturn = $$$hostConfig.writeChunkAndReturn;
36
export const completeWriting = $$$hostConfig.completeWriting;
37
export const flushBuffered = $$$hostConfig.flushBuffered;
38
export const close = $$$hostConfig.close;