From 1bc9c270e001a83e5111bffaaa00dd34cc54ce59 Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 26 Feb 2024 02:00:42 +0100 Subject: [PATCH 01/15] Improve `processWindowErrorEvent` --- web_src/js/bootstrap.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index e46c91e5e6d9..cf78e0a049d1 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -33,7 +33,7 @@ function processWindowErrorEvent(e) { const assetBaseUrl = String(new URL(__webpack_public_path__, window.location.origin)); // error is likely from browser extension or inline script. Do not show these in production builds. - if (!err.stack?.includes(assetBaseUrl) && window.config?.runModeIsProd) return; + if (!err?.stack?.includes(assetBaseUrl) && window.config?.runModeIsProd) return; let message; if (e.type === 'unhandledrejection') { @@ -49,6 +49,7 @@ function processWindowErrorEvent(e) { } showGlobalErrorMessage(`${message} Open browser console to see more details.`); + console.error(err ?? e); } function initGlobalErrorHandler() { From 913be693deb4dbe8c9787daac58d5ce9f73f6ffd Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 26 Feb 2024 20:12:25 +0100 Subject: [PATCH 02/15] rewrite the function, handle all cases --- web_src/js/bootstrap.js | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index cf78e0a049d1..84a667d5361f 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -28,28 +28,29 @@ export function showGlobalErrorMessage(msg) { /** * @param {ErrorEvent} e */ -function processWindowErrorEvent(e) { - const err = e.error ?? e.reason; +function processWindowErrorEvent({error, reason, message, type, filename, lineno, colno}) { + const err = error ?? reason; const assetBaseUrl = String(new URL(__webpack_public_path__, window.location.origin)); - // error is likely from browser extension or inline script. Do not show these in production builds. - if (!err?.stack?.includes(assetBaseUrl) && window.config?.runModeIsProd) return; + // Normally the browser will log the error to the console, but in some cases like "ResizeObserver + // loop completed with undelivered notifications" in Firefox, e.error is undefined, resulting in + // nothing being logged by the browser, so we do it instead. + if (!err && message) console.error(new Error(message)); - let message; - if (e.type === 'unhandledrejection') { - message = `JavaScript promise rejection: ${err.message}.`; - } else { - message = `JavaScript error: ${e.message} (${e.filename} @ ${e.lineno}:${e.colno}).`; - } + // If the error stack trace does not include the base URL of our scripts, it is likely from a + // browser extension or inline script. Do not show these in production builds. + if (!err?.stack?.includes(assetBaseUrl) && window.config?.runModeIsProd) return; - if (!e.error && e.lineno === 0 && e.colno === 0 && e.filename === '' && window.navigator.userAgent.includes('FxiOS/')) { - // At the moment, Firefox (iOS) (10x) has an engine bug. See https://github.com/go-gitea/gitea/issues/20240 - // If a script inserts a newly created (and content changed) element into DOM, there will be a nonsense error event reporting: Script error: line 0, col 0. - return; // ignore such nonsense error event - } + // At the moment, Firefox (iOS) (10x) has an engine bug. If a script inserts a newly created (and + // content changed) element into DOM, there will be a nonsense error event reporting: Script + // error: line 0, col 0, ignore such nonsense error event. + // See https://github.com/go-gitea/gitea/issues/20240 + if (!err && lineno === 0 && colno === 0 && filename === '' && window.navigator.userAgent.includes('FxiOS/')) return; - showGlobalErrorMessage(`${message} Open browser console to see more details.`); - console.error(err ?? e); + const renderedType = type === 'unhandledrejection' ? 'promise rejection' : type; + let msg = err?.message ?? message; + if (lineno) msg += `(${filename} @ ${lineno}:${colno})`; + showGlobalErrorMessage(`JavaScript ${renderedType}: ${msg}. Open browser console to see more details.`); } function initGlobalErrorHandler() { From 4c07e513525b20e445fc8a5dea1336e750bfe3be Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 26 Feb 2024 20:16:13 +0100 Subject: [PATCH 03/15] handle trailing dot in message --- web_src/js/bootstrap.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index 84a667d5361f..d27153153e20 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -50,7 +50,8 @@ function processWindowErrorEvent({error, reason, message, type, filename, lineno const renderedType = type === 'unhandledrejection' ? 'promise rejection' : type; let msg = err?.message ?? message; if (lineno) msg += `(${filename} @ ${lineno}:${colno})`; - showGlobalErrorMessage(`JavaScript ${renderedType}: ${msg}. Open browser console to see more details.`); + const dot = msg.endsWith('.') ? '' : '.'; + showGlobalErrorMessage(`JavaScript ${renderedType}: ${msg}${dot} Open browser console to see more details.`); } function initGlobalErrorHandler() { From a2346aa2a7ac31bcd72eb53aa935ffeae4a0cef6 Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 26 Feb 2024 20:23:36 +0100 Subject: [PATCH 04/15] comment tweaks --- web_src/js/bootstrap.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index d27153153e20..4aeef5d343f6 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -33,12 +33,12 @@ function processWindowErrorEvent({error, reason, message, type, filename, lineno const assetBaseUrl = String(new URL(__webpack_public_path__, window.location.origin)); // Normally the browser will log the error to the console, but in some cases like "ResizeObserver - // loop completed with undelivered notifications" in Firefox, e.error is undefined, resulting in + // loop completed with undelivered notifications" in Firefox, `error is undefined, resulting in // nothing being logged by the browser, so we do it instead. if (!err && message) console.error(new Error(message)); - // If the error stack trace does not include the base URL of our scripts, it is likely from a - // browser extension or inline script. Do not show these in production builds. + // If the error stack trace does not include the base URL of our scripts, it is likely coming from + // a browser extension or inline script. Do not show these in production builds. if (!err?.stack?.includes(assetBaseUrl) && window.config?.runModeIsProd) return; // At the moment, Firefox (iOS) (10x) has an engine bug. If a script inserts a newly created (and From 9b2e79ffab1bc031e3de188544844430c049302e Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 26 Feb 2024 20:23:49 +0100 Subject: [PATCH 05/15] comment tweak --- web_src/js/bootstrap.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index 4aeef5d343f6..4ca58bfa4ae7 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -33,7 +33,7 @@ function processWindowErrorEvent({error, reason, message, type, filename, lineno const assetBaseUrl = String(new URL(__webpack_public_path__, window.location.origin)); // Normally the browser will log the error to the console, but in some cases like "ResizeObserver - // loop completed with undelivered notifications" in Firefox, `error is undefined, resulting in + // loop completed with undelivered notifications" in Firefox, `error` is undefined, resulting in // nothing being logged by the browser, so we do it instead. if (!err && message) console.error(new Error(message)); From 5ce63fb63e725d77c0d334dab756c5cb60a47b23 Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 26 Feb 2024 23:13:18 +0100 Subject: [PATCH 06/15] Update web_src/js/bootstrap.js --- web_src/js/bootstrap.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index 4ca58bfa4ae7..0fc40230a1df 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -38,7 +38,7 @@ function processWindowErrorEvent({error, reason, message, type, filename, lineno if (!err && message) console.error(new Error(message)); // If the error stack trace does not include the base URL of our scripts, it is likely coming from - // a browser extension or inline script. Do not show these in production builds. + // a browser extension or inline script. Do not show such errors in production builds. if (!err?.stack?.includes(assetBaseUrl) && window.config?.runModeIsProd) return; // At the moment, Firefox (iOS) (10x) has an engine bug. If a script inserts a newly created (and From 25d1e1cabbe98c0c7e60de76696363beafaef968 Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 27 Feb 2024 01:11:16 +0100 Subject: [PATCH 07/15] further simplify the handle to show error events only in development --- web_src/js/bootstrap.js | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index 0fc40230a1df..0a0a33a70fa2 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -31,21 +31,23 @@ export function showGlobalErrorMessage(msg) { function processWindowErrorEvent({error, reason, message, type, filename, lineno, colno}) { const err = error ?? reason; const assetBaseUrl = String(new URL(__webpack_public_path__, window.location.origin)); + const {runModeIsProd} = window.config ?? {}; - // Normally the browser will log the error to the console, but in some cases like "ResizeObserver - // loop completed with undelivered notifications" in Firefox, `error` is undefined, resulting in - // nothing being logged by the browser, so we do it instead. - if (!err && message) console.error(new Error(message)); - - // If the error stack trace does not include the base URL of our scripts, it is likely coming from - // a browser extension or inline script. Do not show such errors in production builds. - if (!err?.stack?.includes(assetBaseUrl) && window.config?.runModeIsProd) return; + // The browser will log all `err` that pass this handler to the console, but some cases like + // ResizeObserver [1] or Browser errors [2], [3] don't raise actual errors but only error events + // which don't log to the console by default. We log these errors to the console, and during + // development, they will additionaly show as error message. + // [1] https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver#observation_errors + // [2] https://github.com/mozilla-mobile/firefox-ios/issues/10817 + // [3] https://github.com/go-gitea/gitea/issues/20240 + if (!err && message) { + console.error(new Error(message)); + if (runModeIsProd) return; // don't show error events in production + } - // At the moment, Firefox (iOS) (10x) has an engine bug. If a script inserts a newly created (and - // content changed) element into DOM, there will be a nonsense error event reporting: Script - // error: line 0, col 0, ignore such nonsense error event. - // See https://github.com/go-gitea/gitea/issues/20240 - if (!err && lineno === 0 && colno === 0 && filename === '' && window.navigator.userAgent.includes('FxiOS/')) return; + // If the error stack trace does not include the base URL of our script assets, it likely came + // from a browser extension or inline script. Do not show such errors in production. + if (!err?.stack?.includes(assetBaseUrl) && runModeIsProd) return; const renderedType = type === 'unhandledrejection' ? 'promise rejection' : type; let msg = err?.message ?? message; From ce860cabc11d0ed3b64f2c94d5aac1d86285fbe4 Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 27 Feb 2024 01:17:36 +0100 Subject: [PATCH 08/15] tweak comment --- web_src/js/bootstrap.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index 0a0a33a70fa2..e92a7db3ce2a 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -33,15 +33,15 @@ function processWindowErrorEvent({error, reason, message, type, filename, lineno const assetBaseUrl = String(new URL(__webpack_public_path__, window.location.origin)); const {runModeIsProd} = window.config ?? {}; - // The browser will log all `err` that pass this handler to the console, but some cases like - // ResizeObserver [1] or Browser errors [2], [3] don't raise actual errors but only error events - // which don't log to the console by default. We log these errors to the console, and during - // development, they will additionaly show as error message. - // [1] https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver#observation_errors - // [2] https://github.com/mozilla-mobile/firefox-ios/issues/10817 - // [3] https://github.com/go-gitea/gitea/issues/20240 - if (!err && message) { - console.error(new Error(message)); + // This handler not only receives errors but also error events, detectable by `err` being null + // or undefined. Error events do not log to the browser console by default but as they might + // still be relevant, we show them during development. In production they will only log to the + // console. References and examples: + // - https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver#observation_errors + // - https://github.com/mozilla-mobile/firefox-ios/issues/10817 + // - https://github.com/go-gitea/gitea/issues/20240 + if (!err) { + if (message) console.error(new Error(message)); if (runModeIsProd) return; // don't show error events in production } From c26fb35f42362e66266786bf983d50046957e7f7 Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 27 Feb 2024 02:10:18 +0100 Subject: [PATCH 09/15] Update web_src/js/bootstrap.js --- web_src/js/bootstrap.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index e92a7db3ce2a..f93c40343f12 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -51,7 +51,7 @@ function processWindowErrorEvent({error, reason, message, type, filename, lineno const renderedType = type === 'unhandledrejection' ? 'promise rejection' : type; let msg = err?.message ?? message; - if (lineno) msg += `(${filename} @ ${lineno}:${colno})`; + if (lineno) msg += ` (${filename} @ ${lineno}:${colno})`; const dot = msg.endsWith('.') ? '' : '.'; showGlobalErrorMessage(`JavaScript ${renderedType}: ${msg}${dot} Open browser console to see more details.`); } From 3430adfcb3be72bf8e644912fd05225f00d0ed05 Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 27 Feb 2024 02:11:44 +0100 Subject: [PATCH 10/15] Update web_src/js/bootstrap.js --- web_src/js/bootstrap.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index f93c40343f12..a6377487574b 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -35,8 +35,7 @@ function processWindowErrorEvent({error, reason, message, type, filename, lineno // This handler not only receives errors but also error events, detectable by `err` being null // or undefined. Error events do not log to the browser console by default but as they might - // still be relevant, we show them during development. In production they will only log to the - // console. References and examples: + // still be relevant, we show them during development. References and examples: // - https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver#observation_errors // - https://github.com/mozilla-mobile/firefox-ios/issues/10817 // - https://github.com/go-gitea/gitea/issues/20240 From e8163f9119ecea2db43d7061a67524b25925ef38 Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 27 Feb 2024 02:16:20 +0100 Subject: [PATCH 11/15] wrap comments at 100 chars --- web_src/js/bootstrap.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index a6377487574b..42a5c097de2b 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -1,5 +1,6 @@ // DO NOT IMPORT window.config HERE! -// to make sure the error handler always works, we should never import `window.config`, because some user's custom template breaks it. +// to make sure the error handler always works, we should never import `window.config`, because +// some user's custom template breaks it. // This sets up the URL prefix used in webpack's chunk loading. // This file must be imported before any lazy-loading is being attempted. @@ -33,15 +34,15 @@ function processWindowErrorEvent({error, reason, message, type, filename, lineno const assetBaseUrl = String(new URL(__webpack_public_path__, window.location.origin)); const {runModeIsProd} = window.config ?? {}; - // This handler not only receives errors but also error events, detectable by `err` being null - // or undefined. Error events do not log to the browser console by default but as they might - // still be relevant, we show them during development. References and examples: + // This handler not only receives `Errors`` but also error events, detectable by `error` being + // null or undefined. Error events do not log to the browser console by default but as they may + // might still be relevant, we show them during development. Examples: // - https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver#observation_errors // - https://github.com/mozilla-mobile/firefox-ios/issues/10817 // - https://github.com/go-gitea/gitea/issues/20240 if (!err) { if (message) console.error(new Error(message)); - if (runModeIsProd) return; // don't show error events in production + if (runModeIsProd) return; } // If the error stack trace does not include the base URL of our script assets, it likely came @@ -63,13 +64,14 @@ function initGlobalErrorHandler() { if (!window.config) { showGlobalErrorMessage(`Gitea JavaScript code couldn't run correctly, please check your custom templates`); } - // we added an event handler for window error at the very beginning of