137
return !externalRegExp.test(stackFrame);
138
}
139
140
+function prepareStackTrace(
141
+ error: Error,
142
+ structuredStackTrace: CallSite[],
143
+): string {
144
+ const name = error.name || 'Error';
145
+ const message = error.message || '';
146
+ let stack = name + ': ' + message;
147
+ for (let i = 0; i < structuredStackTrace.length; i++) {
148
+ stack += '\n at ' + structuredStackTrace[i].toString();
149
+ }
150
+ return stack;
151
+}
152
+
153
+function getStack(error: Error): string {
154
+ // We override Error.prepareStackTrace with our own version that normalizes
155
+ // the stack to V8 formatting even if the server uses other formatting.
156
+ // It also ensures that source maps are NOT applied to this since that can
157
+ // be slow we're better off doing that lazily from the client instead of
158
+ // eagerly on the server. If the stack has already been read, then we might
159
+ // not get a normalized stack and it might still have been source mapped.
160
+ // So the client still needs to be resilient to this.
161
+ const previousPrepare = Error.prepareStackTrace;
162
+ Error.prepareStackTrace = prepareStackTrace;
163
+ try {
164
+ // eslint-disable-next-line react-internal/safe-string-coercion
165
+ return String(error.stack);
166
+ } finally {
167
+ Error.prepareStackTrace = previousPrepare;
168
+ }
169
+}
170
+
171
function initCallComponentFrame(): string {
172
// Extract the stack frame of the callComponentInDEV function.
173
const error = callComponentInDEV(Error, 'react-stack-top-frame', {});
143
- const stack = error.stack;
174
+ const stack = getStack(error);
175
const startIdx = stack.startsWith('Error: react-stack-top-frame\n') ? 29 : 0;
176
const endIdx = stack.indexOf('\n', startIdx);
177
if (endIdx === -1) {
186
(callIteratorInDEV: any)({next: null});
187
return '';
188
} catch (error) {
158
- const stack = error.stack;
189
+ const stack = getStack(error);
190
const startIdx = stack.startsWith('TypeError: ')
191
? stack.indexOf('\n') + 1
192
: 0;
205
_init: Error,
206
_payload: 'react-stack-top-frame',
207
});
177
- const stack = error.stack;
208
+ const stack = getStack(error);
209
const startIdx = stack.startsWith('Error: react-stack-top-frame\n') ? 29 : 0;
210
const endIdx = stack.indexOf('\n', startIdx);
211
if (endIdx === -1) {
219
// to save bandwidth even in DEV. We'll also replay these stacks on the client so by
220
// stripping them early we avoid that overhead. Otherwise we'd normally just rely on
221
// the DevTools or framework's ignore lists to filter them out.
191
- let stack = error.stack;
222
+ let stack = getStack(error);
223
if (stack.startsWith('Error: react-stack-top-frame\n')) {
224
// V8's default formatting prefixes with the error message which we
225
// don't want/need.
2632
try {
2633
// eslint-disable-next-line react-internal/safe-string-coercion
2634
reason = String(postponeInstance.message);
2604
- // eslint-disable-next-line react-internal/safe-string-coercion
2605
- stack = String(postponeInstance.stack);
2635
+ stack = getStack(postponeInstance);
2636
} catch (x) {}
2637
row = serializeRowHeader('P', id) + stringify({reason, stack}) + '\n';
2638
} else {
2657
if (error instanceof Error) {
2658
// eslint-disable-next-line react-internal/safe-string-coercion
2659
message = String(error.message);
2630
- // eslint-disable-next-line react-internal/safe-string-coercion
2631
- stack = String(error.stack);
2660
+ stack = getStack(error);
2661
} else if (typeof error === 'object' && error !== null) {
2662
message = describeObjectForErrorMessage(error);
2663
} else {