[Flight] Encode the name of a function as an object property (#30325)
Unfortunately, Firefox doesn't include the name of a function in stack traces if you set it as either `.name` or `.displayName` at runtime. Only if you include it declarative. We also can't include it into a named function expression because not all possible names are expressible declaratively. E.g. spaces or punctuations. However, we can express any name if it's an object property and since object properties now give their name declarative to the function defined inside of them, we can declaratively express any name this way.
Sebastian Markbåge committed
Jul 13, 2024 at 16:33 UTC
8b08e99efa56b848538768e25265fd3aa24dd8a1
1 file changed
+18
-8
packages/react-client/src/ReactFlightClient.js
+18
-8
@@ -1891,19 +1891,33 @@ function createFakeFunction<T>(
1891
const comment =
1892
'/* This module was rendered by a Server Component. Turn on Source Maps to see the server source. */';
1893
1894
+ if (!name) {
1895
+ // An eval:ed function with no name gets the name "eval". We give it something more descriptive.
1896
+ name = '(anonymous)';
1897
+ }
1898
+ const encodedName = JSON.stringify(name);
1899
// We generate code where the call is at the line and column of the server executed code.
1900
// This allows us to use the original source map as the source map of this fake file to
1901
// point to the original source.
1902
let code;
1903
if (line <= 1) {
1899
- code = '_=>' + ' '.repeat(col < 4 ? 0 : col - 4) + '_()\n' + comment;
1904
+ const minSize = encodedName.length + 7;
1905
+ code =
1906
+ '({' +
1907
+ encodedName +
1908
+ ':_=>' +
1909
+ ' '.repeat(col < minSize ? 0 : col - minSize) +
1910
+ '_()})\n' +
1911
+ comment;
1912
} else {
1913
code =
1914
comment +
1915
'\n'.repeat(line - 2) +
1904
- '_=>\n' +
1916
+ '({' +
1917
+ encodedName +
1918
+ ':_=>\n' +
1919
' '.repeat(col < 1 ? 0 : col - 1) +
1906
- '_()';
1920
+ '_()})';
1921
}
1922
1923
if (filename.startsWith('/')) {
@@ -1931,7 +1945,7 @@ function createFakeFunction<T>(
1945
let fn: FakeFunction<T>;
1946
try {
1947
// eslint-disable-next-line no-eval
1934
- fn = (0, eval)(code);
1948
+ fn = (0, eval)(code)[name];
1949
} catch (x) {
1950
// If eval fails, such as if in an environment that doesn't support it,
1951
// we fallback to creating a function here. It'll still have the right
@@ -1940,10 +1954,6 @@ function createFakeFunction<T>(
1954
return _();
1955
};
1956
}
1943
- // $FlowFixMe[cannot-write]
1944
- Object.defineProperty(fn, 'name', {value: name || '(anonymous)'});
1945
- // $FlowFixMe[prop-missing]
1946
- fn.displayName = name;
1957
return fn;
1958
}
1959