Skip to content

Commit 75c9788

Browse files
authored
task: Expand error reporting (#234)
* task: Log global errors and unhandled rejections Improve observability of errors that occur outside of the React tree and its `ErrorBoundary`. * refactor: Extract global error handler logic * refactor: Remove unnecessary comments * refactor: Remover redundant and erroneous `/gutenberg/` check This path is not used by the project and had not impact. The `window.location.origin` is what achieved the correct outcome. * refactor: Simplify external error check logic * refactor: Rename setUpGlobalErrorHandlers * refactor: Set up global error handlers earlier Avoid missing error occurring during editor initialization.
1 parent 290c207 commit 75c9788

File tree

2 files changed

+89
-0
lines changed

2 files changed

+89
-0
lines changed

src/utils/editor-environment.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { loadEditorAssets } from './editor-loader';
66
import { initializeVideoPressAjaxBridge } from './videopress-bridge';
77
import EditorLoadError from '../components/editor-load-error';
88
import { error } from './logger';
9+
import { setUpGlobalErrorHandlers } from './global-error-handler';
910
import './editor-styles';
1011

1112
/**
@@ -15,6 +16,8 @@ import './editor-styles';
1516
* @return {Promise} Promise that resolves when initialization is complete
1617
*/
1718
export function setUpEditorEnvironment() {
19+
setUpGlobalErrorHandlers();
20+
1821
// Detect platform and add class to body for platform-specific styling
1922
if ( typeof window !== 'undefined' && window.webkit ) {
2023
document.body.classList.add( 'is-ios' );

src/utils/global-error-handler.js

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/**
2+
* Internal dependencies
3+
*/
4+
import { logException } from './bridge';
5+
6+
/**
7+
* Sets up global error handlers to catch and report unhandled errors
8+
* and promise rejections.
9+
*/
10+
export function setUpGlobalErrorHandlers() {
11+
// Catch unhandled errors
12+
window.addEventListener( 'error', ( event ) => {
13+
if ( isExternalError( event.filename, event.error ) ) {
14+
return;
15+
}
16+
17+
const errorObj = event.error || new Error( event.message );
18+
19+
logException( errorObj, {
20+
context: {
21+
filename: event.filename,
22+
lineno: event.lineno,
23+
colno: event.colno,
24+
},
25+
tags: {},
26+
isHandled: false,
27+
handledBy: 'window.error',
28+
} );
29+
} );
30+
31+
// Catch unhandled promise rejections
32+
window.addEventListener( 'unhandledrejection', ( event ) => {
33+
// Convert rejection reason to Error if it isn't already
34+
const errorObj =
35+
event.reason instanceof Error
36+
? event.reason
37+
: new Error( String( event.reason ) );
38+
39+
if ( isExternalError( undefined, errorObj ) ) {
40+
return;
41+
}
42+
43+
logException( errorObj, {
44+
context: {},
45+
tags: {},
46+
isHandled: false,
47+
handledBy: 'unhandledrejection',
48+
} );
49+
} );
50+
}
51+
52+
/**
53+
* Determines if an error originated from an external third-party script.
54+
*
55+
* Detects external HTTP(S) URLs from different origins (third-party scripts).
56+
* GutenbergKit errors (same-origin, file://, or unknown sources) return false.
57+
*
58+
* @param {string|undefined} filename - The filename from the error event
59+
* @param {Error|undefined} errorObj - The error object with stack trace
60+
* @return {boolean} True if the error is from an external source (should be filtered)
61+
*/
62+
function isExternalError( filename, errorObj ) {
63+
// Detect external HTTP(S) URLs from different origins (third-party scripts)
64+
if (
65+
filename?.startsWith( 'http' ) &&
66+
! filename.includes( window.location.origin )
67+
) {
68+
return true;
69+
}
70+
71+
// Check stack trace for external URLs
72+
if ( errorObj?.stack ) {
73+
const stackLines = errorObj.stack.split( '\n' );
74+
for ( const line of stackLines ) {
75+
// Check if any line in stack contains external HTTP URL
76+
if (
77+
line.includes( 'http' ) &&
78+
! line.includes( window.location.origin )
79+
) {
80+
return true;
81+
}
82+
}
83+
}
84+
85+
return false;
86+
}

0 commit comments

Comments
 (0)