Skip to content

Commit 67f7d47

Browse files
authored
[Flight] Fix debug info filtering to include later resolved I/O (facebook#35036)
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 67f7d47

File tree

2 files changed

+45
-58
lines changed

2 files changed

+45
-58
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 doesn't need to 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: 42 additions & 54 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,40 @@ describe('ReactFlightDOMNode', () => {
12421235
);
12431236
}
12441237

1245-
const stream = await ReactServerDOMServer.renderToPipeableStream(
1246-
ReactServer.createElement(App),
1247-
webpackMap,
1248-
{filterStackFrame},
1249-
);
1250-
1238+
let staticEndTime = -1;
12511239
const initialChunks = [];
12521240
const dynamicChunks = [];
1253-
let isDynamic = false;
12541241

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

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

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

1268-
await new Promise(resolve => {
1269-
setTimeout(() => {
1270-
resolveRuntimeData('Hi');
1261+
passThrough.on('end', resolve);
12711262
});
12721263
setTimeout(() => {
1273-
isDynamic = true;
1274-
endTime = performance.now() + performance.timeOrigin;
1275-
resolveDynamicData('Josh');
1276-
resolve();
1264+
staticEndTime = performance.now() + performance.timeOrigin;
1265+
resolveDynamicData1('Hi');
1266+
setTimeout(() => {
1267+
resolveDynamicData2('Josh');
1268+
});
12771269
});
12781270
});
12791271

1280-
await new Promise(resolve => {
1281-
passThrough.on('end', resolve);
1282-
});
1283-
12841272
// Create a new Readable and push all initial chunks immediately.
12851273
const readable = new Stream.Readable({...streamOptions, read() {}});
12861274
for (let i = 0; i < initialChunks.length; i++) {
@@ -1311,8 +1299,8 @@ describe('ReactFlightDOMNode', () => {
13111299
},
13121300
{
13131301
// Debug info arriving after this end time will be ignored, e.g. the
1314-
// I/O info for the dynamic data.
1315-
endTime,
1302+
// I/O info for the second dynamic data.
1303+
endTime: staticEndTime,
13161304
},
13171305
);
13181306

@@ -1358,12 +1346,12 @@ describe('ReactFlightDOMNode', () => {
13581346
'\n' +
13591347
' in Dynamic' +
13601348
(gate(flags => flags.enableAsyncDebugInfo)
1361-
? ' (file://ReactFlightDOMNode-test.js:1223:33)\n'
1349+
? ' (file://ReactFlightDOMNode-test.js:1216:27)\n'
13621350
: '\n') +
13631351
' in body\n' +
13641352
' in html\n' +
1365-
' in App (file://ReactFlightDOMNode-test.js:1240:25)\n' +
1366-
' in ClientRoot (ReactFlightDOMNode-test.js:1320:16)',
1353+
' in App (file://ReactFlightDOMNode-test.js:1233:25)\n' +
1354+
' in ClientRoot (ReactFlightDOMNode-test.js:1308:16)',
13671355
);
13681356
} else {
13691357
expect(
@@ -1372,7 +1360,7 @@ describe('ReactFlightDOMNode', () => {
13721360
'\n' +
13731361
' in body\n' +
13741362
' in html\n' +
1375-
' in ClientRoot (ReactFlightDOMNode-test.js:1320:16)',
1363+
' in ClientRoot (ReactFlightDOMNode-test.js:1308:16)',
13761364
);
13771365
}
13781366

@@ -1382,16 +1370,16 @@ describe('ReactFlightDOMNode', () => {
13821370
normalizeCodeLocInfo(ownerStack, {preserveLocation: true}),
13831371
).toBe(
13841372
'\n' +
1385-
' in Dynamic (file://ReactFlightDOMNode-test.js:1223:33)\n' +
1386-
' in App (file://ReactFlightDOMNode-test.js:1240:25)',
1373+
' in Dynamic (file://ReactFlightDOMNode-test.js:1216:27)\n' +
1374+
' in App (file://ReactFlightDOMNode-test.js:1233:25)',
13871375
);
13881376
} else {
13891377
expect(
13901378
normalizeCodeLocInfo(ownerStack, {preserveLocation: true}),
13911379
).toBe(
13921380
'' +
13931381
'\n' +
1394-
' in App (file://ReactFlightDOMNode-test.js:1240:25)',
1382+
' in App (file://ReactFlightDOMNode-test.js:1233:25)',
13951383
);
13961384
}
13971385
} else {

0 commit comments

Comments
 (0)