@samitouri / QOS-React-2 / commits / b3e0a11e8f

[Flight] Allow <anonymous> stack frames to be serialized if opt-in (#31329)

Normally we filter out stack frames with missing `filename` because they can be noisy and not ignore listed. However, it's up to the filterStackFrame function to determine whether to do it. This lets us match `<anonymous>` stack frames in V8 parsing (they don't have line numbers).

Sebastian Markbåge committed Oct 23, 2024 at 08:38 UTC b3e0a11e8f0689b38a9beec032c0a51cf381e998
3 files changed +20 -3
packages/react-client/src/ReactFlightClient.js
+2
@@ -2281,6 +2281,8 @@ function createFakeFunction<T>(
2281 code += '\n//# sourceMappingURL=' + sourceMap;
2282 } else if (filename) {
2283 code += '\n//# sourceURL=' + filename;
2284 + } else {
2285 + code += '\n//# sourceURL=<anonymous>';
2286 }
2287
2288 let fn: FakeFunction<T>;
packages/react-client/src/__tests__/ReactFlight-test.js
+17 -2
@@ -1282,6 +1282,8 @@ describe('ReactFlight', () => {
1282 ' at file:///testing.js:42:3',
1283 // async anon function (https://github.com/ChromeDevTools/devtools-frontend/blob/831be28facb4e85de5ee8c1acc4d98dfeda7a73b/test/unittests/front_end/panels/console/ErrorStackParser_test.ts#L130C9-L130C41)
1284 ' at async file:///testing.js:42:3',
1285 + // host component in parent stack
1286 + ' at div (<anonymous>)',
1287 ...originalStackLines.slice(2),
1288 ].join('\n');
1289 throw error;
@@ -1328,6 +1330,15 @@ describe('ReactFlight', () => {
1330 }
1331 return `digest(${String(x)})`;
1332 },
1333 + filterStackFrame(filename, functionName) {
1334 + if (!filename) {
1335 + // Allow anonymous
1336 + return functionName === 'div';
1337 + }
1338 + return (
1339 + !filename.startsWith('node:') && !filename.includes('node_modules')
1340 + );
1341 + },
1342 });
1343
1344 await act(() => {
@@ -1355,14 +1366,16 @@ describe('ReactFlight', () => {
1366 ' at eval (eval at testFunction (eval at createFakeFunction (**), <anonymous>:1:35)\n' +
1367 ' at ServerComponentError (file://~/(some)(really)(exotic-directory)/ReactFlight-test.js:1166:19)\n' +
1368 ' at <anonymous> (file:///testing.js:42:3)\n' +
1358 - ' at <anonymous> (file:///testing.js:42:3)\n',
1369 + ' at <anonymous> (file:///testing.js:42:3)\n' +
1370 + ' at div (<anonymous>',
1371 )
1372 : expect.stringContaining(
1373 'Error: This is an error\n' +
1374 ' at eval (eval at testFunction (inspected-page.html:29:11), <anonymous>:1:10)\n' +
1375 ' at ServerComponentError (file://~/(some)(really)(exotic-directory)/ReactFlight-test.js:1166:19)\n' +
1376 ' at file:///testing.js:42:3\n' +
1365 - ' at file:///testing.js:42:3',
1377 + ' at file:///testing.js:42:3\n' +
1378 + ' at div (<anonymous>',
1379 ),
1380 digest: 'a dev digest',
1381 environmentName: 'Server',
@@ -1379,6 +1392,7 @@ describe('ReactFlight', () => {
1392 'Server',
1393 ],
1394 ['file:///testing.js', 'Server'],
1395 + ['', 'Server'],
1396 [__filename, 'Server'],
1397 ]
1398 : gate(flags => flags.enableServerComponentLogs)
@@ -1390,6 +1404,7 @@ describe('ReactFlight', () => {
1404 'Server',
1405 ],
1406 ['file:///testing.js', 'Server'],
1407 + ['', 'Server'],
1408 ]
1409 : [],
1410 });
packages/react-server/src/ReactFlightStackConfigV8.js
+1 -1
@@ -44,7 +44,7 @@ function getStack(error: Error): string {
44 // at filename:0:0
45 // at async filename:0:0
46 const frameRegExp =
47 - /^ {3} at (?:(.+) \((.+):(\d+):(\d+)\)|(?:async )?(.+):(\d+):(\d+))$/;
47 + /^ {3} at (?:(.+) \((?:(.+):(\d+):(\d+)|\<anonymous\>)\)|(?:async )?(.+):(\d+):(\d+)|\<anonymous\>)$/;
48
49 export function parseStackTrace(
50 error: Error,