From 1470e2986e18581a0867d5147761e772691dab65 Mon Sep 17 00:00:00 2001 From: "Anders D. Johnson" Date: Wed, 7 Jun 2023 20:44:15 -0500 Subject: [PATCH] feat: add component stack to recoverable error Attaches any component stack from error info to the error object on a recoverable error. This will help understanding hydration mismatch errors in production logs. --- .../next/src/client/on-recoverable-error.ts | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/next/src/client/on-recoverable-error.ts b/packages/next/src/client/on-recoverable-error.ts index a58f52ce29dfb..e6ddda3cf8822 100644 --- a/packages/next/src/client/on-recoverable-error.ts +++ b/packages/next/src/client/on-recoverable-error.ts @@ -1,6 +1,22 @@ import { NEXT_DYNAMIC_NO_SSR_CODE } from '../shared/lib/lazy-dynamic/no-ssr-error' -export default function onRecoverableError(err: any) { +/** + * @see [ReactInternalTypes]{@link https://github.com/facebook/react/blob/910045696bb5f693acb77890e6750c5e4659b420/packages/react-reconciler/src/ReactInternalTypes.js#L278-L281} + */ +interface ErrorInfo { + componentStack?: string +} + +export default function onRecoverableError(err: any, errorInfo: ErrorInfo) { + // Attach any component stack to the error, so it's accessible when passed thru `reportError` below, + // such as from custom `window.onerror` or `window` `error` event listeners in an app. + // Similar is done in `@next/react-dev-overlay`, but this supports production use cases as well. + // This is technically a mutation of an argument, which is generally inadvisable, but probably not problematic in this case. + // The alternative of constucting a new error could be more complicated. + if (errorInfo.componentStack) { + err._componentStack = errorInfo.componentStack + } + // Using default react onRecoverableError // x-ref: https://github.com/facebook/react/blob/d4bc16a7d69eb2ea38a88c8ac0b461d5f72cdcab/packages/react-dom/src/client/ReactDOMRoot.js#L83 const defaultOnRecoverableError = @@ -8,11 +24,12 @@ export default function onRecoverableError(err: any) { ? // In modern browsers, reportError will dispatch an error event, // emulating an uncaught JavaScript error. reportError - : (error: any) => { - window.console.error(error) + : (error: any, errorInfo: ErrorInfo) => { + window.console.error(error, errorInfo) } // Skip certain custom errors which are not expected to be reported on client if (err.digest === NEXT_DYNAMIC_NO_SSR_CODE) return - defaultOnRecoverableError(err) + + defaultOnRecoverableError(err, errorInfo) }