Skip to content

Commit 8815f2c

Browse files
committed
[Flight] Fix debug info filtering to include later resolved I/O
In facebook#35019, we excluded debug I/O info from being considered for enhancing the owner stack if it resolved after the defined `endTime` option that can be passed to the Flight client. However, we should include any I/O that was awaited before that end time, even if it resolved later.
1 parent 561ee24 commit 8815f2c

File tree

2 files changed

+46
-57
lines changed

2 files changed

+46
-57
lines changed

packages/react-client/src/ReactFlightClient.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,9 @@ function filterDebugInfo(
510510
return;
511511
}
512512

513-
// Remove any debug info entries that arrived after the defined end time.
513+
// Remove any debug info entries after the defined end time. For async info
514+
// that means, we're including anything that was awaited before the end time,
515+
// but it must not be resolved before the end time.
514516
const relativeEndTime =
515517
response._debugEndTime -
516518
// $FlowFixMe[prop-missing]
@@ -521,9 +523,6 @@ function filterDebugInfo(
521523
if (typeof info.time === 'number' && info.time > relativeEndTime) {
522524
break;
523525
}
524-
if (info.awaited != null && info.awaited.end > relativeEndTime) {
525-
break;
526-
}
527526
debugInfo.push(info);
528527
}
529528
value._debugInfo = debugInfo;

packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js

Lines changed: 43 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,35 +1197,28 @@ describe('ReactFlightDOMNode', () => {
11971197
});
11981198

11991199
it('should use late-arriving I/O debug info to enhance component and owner stacks when aborting a prerender', async () => {
1200-
// This test is constructing a scenario where a framework might separate
1201-
// I/O into different phases, e.g. runtime I/O and dynamic I/O. The
1202-
// framework might choose to define an end time for the Flight client,
1203-
// indicating that all I/O info (or any debug info for that matter) that
1204-
// arrives after that time should be ignored. When rendering in Fizz is
1205-
// then aborted, the late-arriving debug info that's used to enhance the
1206-
// owner stack only includes I/O info up to that end time.
1207-
let resolveRuntimeData;
1208-
let resolveDynamicData;
1209-
1210-
async function getRuntimeData() {
1200+
let resolveDynamicData1;
1201+
let resolveDynamicData2;
1202+
1203+
async function getDynamicData1() {
12111204
return new Promise(resolve => {
1212-
resolveRuntimeData = resolve;
1205+
resolveDynamicData1 = resolve;
12131206
});
12141207
}
12151208

1216-
async function getDynamicData() {
1209+
async function getDynamicData2() {
12171210
return new Promise(resolve => {
1218-
resolveDynamicData = resolve;
1211+
resolveDynamicData2 = resolve;
12191212
});
12201213
}
12211214

12221215
async function Dynamic() {
1223-
const runtimeData = await getRuntimeData();
1224-
const dynamicData = await getDynamicData();
1216+
const data1 = await getDynamicData1();
1217+
const data2 = await getDynamicData2();
12251218

12261219
return (
12271220
<p>
1228-
{runtimeData} {dynamicData}
1221+
{data1} {data2}
12291222
</p>
12301223
);
12311224
}
@@ -1242,45 +1235,42 @@ describe('ReactFlightDOMNode', () => {
12421235
);
12431236
}
12441237

1245-
const stream = await ReactServerDOMServer.renderToPipeableStream(
1246-
ReactServer.createElement(App),
1247-
webpackMap,
1248-
{filterStackFrame},
1249-
);
1238+
let passThrough;
1239+
let staticEndTime = -1;
12501240

12511241
const initialChunks = [];
12521242
const dynamicChunks = [];
1253-
let isDynamic = false;
12541243

1255-
const passThrough = new Stream.PassThrough(streamOptions);
1256-
stream.pipe(passThrough);
1244+
await new Promise(resolve => {
1245+
setTimeout(async () => {
1246+
const stream = ReactServerDOMServer.renderToPipeableStream(
1247+
ReactServer.createElement(App),
1248+
webpackMap,
1249+
{filterStackFrame},
1250+
);
12571251

1258-
passThrough.on('data', chunk => {
1259-
if (isDynamic) {
1260-
dynamicChunks.push(chunk);
1261-
} else {
1262-
initialChunks.push(chunk);
1263-
}
1264-
});
1252+
passThrough = new Stream.PassThrough(streamOptions);
1253+
stream.pipe(passThrough);
12651254

1266-
let endTime;
1255+
passThrough.on('data', chunk => {
1256+
if (staticEndTime < 0) {
1257+
initialChunks.push(chunk);
1258+
} else {
1259+
dynamicChunks.push(chunk);
1260+
}
1261+
});
12671262

1268-
await new Promise(resolve => {
1269-
setTimeout(() => {
1270-
resolveRuntimeData('Hi');
1263+
passThrough.on('end', resolve);
12711264
});
12721265
setTimeout(() => {
1273-
isDynamic = true;
1274-
endTime = performance.now() + performance.timeOrigin;
1275-
resolveDynamicData('Josh');
1276-
resolve();
1266+
staticEndTime = performance.now() + performance.timeOrigin;
1267+
resolveDynamicData1('Hi');
1268+
setTimeout(() => {
1269+
resolveDynamicData2('Josh');
1270+
});
12771271
});
12781272
});
12791273

1280-
await new Promise(resolve => {
1281-
passThrough.on('end', resolve);
1282-
});
1283-
12841274
// Create a new Readable and push all initial chunks immediately.
12851275
const readable = new Stream.Readable({...streamOptions, read() {}});
12861276
for (let i = 0; i < initialChunks.length; i++) {
@@ -1311,8 +1301,8 @@ describe('ReactFlightDOMNode', () => {
13111301
},
13121302
{
13131303
// Debug info arriving after this end time will be ignored, e.g. the
1314-
// I/O info for the dynamic data.
1315-
endTime,
1304+
// I/O info for the second dynamic data.
1305+
endTime: staticEndTime,
13161306
},
13171307
);
13181308

@@ -1358,12 +1348,12 @@ describe('ReactFlightDOMNode', () => {
13581348
'\n' +
13591349
' in Dynamic' +
13601350
(gate(flags => flags.enableAsyncDebugInfo)
1361-
? ' (file://ReactFlightDOMNode-test.js:1223:33)\n'
1351+
? ' (file://ReactFlightDOMNode-test.js:1216:27)\n'
13621352
: '\n') +
13631353
' in body\n' +
13641354
' in html\n' +
1365-
' in App (file://ReactFlightDOMNode-test.js:1240:25)\n' +
1366-
' in ClientRoot (ReactFlightDOMNode-test.js:1320:16)',
1355+
' in App (file://ReactFlightDOMNode-test.js:1233:25)\n' +
1356+
' in ClientRoot (ReactFlightDOMNode-test.js:1310:16)',
13671357
);
13681358
} else {
13691359
expect(
@@ -1372,7 +1362,7 @@ describe('ReactFlightDOMNode', () => {
13721362
'\n' +
13731363
' in body\n' +
13741364
' in html\n' +
1375-
' in ClientRoot (ReactFlightDOMNode-test.js:1320:16)',
1365+
' in ClientRoot (ReactFlightDOMNode-test.js:1310:16)',
13761366
);
13771367
}
13781368

@@ -1382,16 +1372,16 @@ describe('ReactFlightDOMNode', () => {
13821372
normalizeCodeLocInfo(ownerStack, {preserveLocation: true}),
13831373
).toBe(
13841374
'\n' +
1385-
' in Dynamic (file://ReactFlightDOMNode-test.js:1223:33)\n' +
1386-
' in App (file://ReactFlightDOMNode-test.js:1240:25)',
1375+
' in Dynamic (file://ReactFlightDOMNode-test.js:1216:27)\n' +
1376+
' in App (file://ReactFlightDOMNode-test.js:1233:25)',
13871377
);
13881378
} else {
13891379
expect(
13901380
normalizeCodeLocInfo(ownerStack, {preserveLocation: true}),
13911381
).toBe(
13921382
'' +
13931383
'\n' +
1394-
' in App (file://ReactFlightDOMNode-test.js:1240:25)',
1384+
' in App (file://ReactFlightDOMNode-test.js:1233:25)',
13951385
);
13961386
}
13971387
} else {

0 commit comments

Comments
 (0)