Skip to content

Commit 83e6324

Browse files
committed
Add support for facebook/react#9679
1 parent cd9c43f commit 83e6324

File tree

3 files changed

+60
-33
lines changed

3 files changed

+60
-33
lines changed
Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,42 @@
11
/* @flow */
2-
type ConsoleProxyCallback = (message: string) => void;
2+
3+
type ReactFrame = {
4+
fileName: string | null,
5+
lineNumber: number | null,
6+
functionName: string | null,
7+
};
8+
const ReactFrameStack: Array<ReactFrame[]> = [];
9+
10+
export type { ReactFrame };
11+
12+
const registerReactStack = () => {
13+
// $FlowFixMe
14+
console.stack = frames => ReactFrameStack.push(frames);
15+
// $FlowFixMe
16+
console.stackEnd = frames => ReactFrameStack.pop();
17+
};
18+
19+
const unregisterReactStack = () => {
20+
// $FlowFixMe
21+
console.stack = undefined;
22+
// $FlowFixMe
23+
console.stackEnd = undefined;
24+
};
25+
26+
type ConsoleProxyCallback = (
27+
message: string,
28+
frames: ReactFrame[] | void
29+
) => void;
330
const permanentRegister = function proxyConsole(
431
type: string,
532
callback: ConsoleProxyCallback
633
) {
734
const orig = console[type];
835
console[type] = function __stack_frame_overlay_proxy_console__() {
936
const message = [].slice.call(arguments).join(' ');
10-
callback(message);
37+
callback(message, ReactFrameStack[ReactFrameStack.length - 1]);
1138
return orig.apply(this, arguments);
1239
};
1340
};
1441

15-
export { permanentRegister };
42+
export { permanentRegister, registerReactStack, unregisterReactStack };

packages/react-error-overlay/src/overlay.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import {
2121
} from './effects/stackTraceLimit';
2222
import {
2323
permanentRegister as permanentRegisterConsole,
24+
registerReactStack,
25+
unregisterReactStack,
2426
} from './effects/proxyConsole';
2527
import { massage as massageWarning } from './utils/warnings';
2628

@@ -213,8 +215,9 @@ function inject() {
213215
registerShortcuts(window, shortcutHandler);
214216
registerStackTraceLimit();
215217

216-
permanentRegisterConsole('error', warning => {
217-
const data = massageWarning(warning);
218+
registerReactStack();
219+
permanentRegisterConsole('error', (warning, stack) => {
220+
const data = massageWarning(warning, stack);
218221
if (data == null) return;
219222
crash(
220223
// $FlowFixMe
@@ -233,6 +236,7 @@ function uninject() {
233236
unregisterShortcuts(window);
234237
unregisterPromise(window);
235238
unregisterError(window);
239+
unregisterReactStack();
236240
}
237241

238242
export { inject, uninject };

packages/react-error-overlay/src/utils/warnings.js

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,38 @@
11
// @flow
2+
import type { ReactFrame } from '../effects/proxyConsole';
23

3-
// This is a list of React warnings to display
4-
// There must be zero or one capture group; and the capture group is assumed to be a missing stack frame.
5-
const warnings = [
6-
/^.*React.createElement: type is invalid.+Check your code at (.*?:.*)[.]$/,
7-
];
8-
// This is a list of information to remove from React warnings, it's not particularly useful to show
4+
// This is a list of information to remove from React warnings, it's not particularly useful to show.
95
const removals = [/Check your code at (.*?:.*)[.]/];
106

11-
function massage(warning: string): { message: string, stack: string } | null {
12-
const nIndex = warning.indexOf('\n');
13-
let message = warning;
14-
if (nIndex !== -1) {
15-
message = message.substring(0, nIndex);
16-
}
17-
let stack = warning.substring(nIndex + 1);
18-
19-
let found = false;
20-
for (const warning of warnings) {
21-
const m = message.match(warning);
22-
if (!m) {
23-
continue;
24-
}
25-
found = true;
26-
if (!m[1]) {
27-
break;
28-
}
29-
stack = `in (render function) (at ${m[1]})\n${stack}`;
30-
break;
31-
}
32-
if (!found) {
7+
function massage(
8+
warning: string,
9+
frames: ReactFrame[] | void
10+
): { message: string, stack: string } | null {
11+
if (!frames) {
3312
return null;
3413
}
3514

15+
let message = warning;
16+
const nIndex = message.indexOf('\n');
17+
if (nIndex !== -1) message = message.substring(0, nIndex);
18+
3619
for (const trim of removals) {
3720
message = message.replace(trim, '');
3821
}
3922

23+
let stack = '';
24+
for (let index = 0; index < frames.length; ++index) {
25+
const { fileName, lineNumber } = frames[index];
26+
if (fileName == null || lineNumber == null) continue;
27+
let { functionName } = frames[index];
28+
if (functionName == null && index === 0 && index + 1 < frames.length) {
29+
functionName = frames[index + 1].functionName;
30+
if (functionName !== null) functionName = `(${functionName})`;
31+
}
32+
functionName = functionName || '(unknown function)';
33+
34+
stack += `in ${functionName} (at ${fileName}:${lineNumber})\n`;
35+
}
4036
return { message, stack };
4137
}
4238

0 commit comments

Comments
 (0)