Skip to content

Commit

Permalink
handle error console instance and title
Browse files Browse the repository at this point in the history
  • Loading branch information
huozhi committed Nov 7, 2024
1 parent 6a0102a commit beb2b74
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 43 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import isError from '../../../lib/is-error'
import { isNextRouterError } from '../is-next-router-error'
import { captureStackTrace } from '../react-dev-overlay/internal/helpers/capture-stack-trace'
import { handleClientError } from '../react-dev-overlay/internal/helpers/use-error-handler'

export const originConsoleError = window.console.error
Expand All @@ -13,13 +12,12 @@ export function patchConsoleError() {
}
window.console.error = function error(...args: any[]) {
let maybeError: unknown
let isReplayedError = false

if (process.env.NODE_ENV !== 'production') {
const replayedError = matchReplayedError(...args)
if (replayedError) {
isReplayedError = true
maybeError = replayedError
} else if (isError(args[0])) {
maybeError = args[0]
} else {
// See https://github.com/facebook/react/blob/d50323eb845c5fde0d720cae888bf35dedd05506/packages/react-reconciler/src/ReactFiberErrorLogger.js#L78
maybeError = args[1]
Expand All @@ -30,16 +28,12 @@ export function patchConsoleError() {

if (!isNextRouterError(maybeError)) {
if (process.env.NODE_ENV !== 'production') {
// Create an origin stack that pointing to the origin location of the error
if (!isReplayedError && isError(maybeError)) {
captureStackTrace(maybeError)
}

handleClientError(
// replayed errors have their own complex format string that should be used,
// but if we pass the error directly, `handleClientError` will ignore it
maybeError,
args
args,
true
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ import {
} from '../helpers/hydration-error-info'
import { NodejsInspectorCopyButton } from '../components/nodejs-inspector'
import { CopyButton } from '../components/copy-button'
import { isUnhandledConsoleOrRejection } from '../helpers/console-error'
import {
getUnhandledErrorType,
isUnhandledConsoleOrRejection,
} from '../helpers/console-error'

export type SupportedErrorEvent = {
id: number
Expand Down Expand Up @@ -62,12 +65,19 @@ function ErrorDescription({
hydrationWarning: string | null
}) {
const isUnhandledOrReplayError = isUnhandledConsoleOrRejection(error)
const unhandledErrorType = isUnhandledOrReplayError
? getUnhandledErrorType(error)
: null
const isConsoleErrorStringMessage = unhandledErrorType === 'string'
// If the error is:
// - hydration warning
// - captured console error or unhandled rejection
// skip displaying the error name
const title =
isUnhandledOrReplayError || hydrationWarning ? '' : error.name + ': '
(isUnhandledOrReplayError && isConsoleErrorStringMessage) ||
hydrationWarning
? ''
: error.name + ': '

// If it's replayed error, display the environment name
const environmentName =
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
// To distinguish from React error.digest, we use a different symbol here to determine if the error is from console.error or unhandled promise rejection.
const digestSym = Symbol.for('next.console.error.digest')
const consoleTypeSym = Symbol.for('next.console.error.type')

// Represent non Error shape unhandled promise rejections or console.error errors.
// Those errors will be captured and displayed in Error Overlay.
type UnhandledError = Error & { digest: 'NEXT_UNHANDLED_ERROR' }
type UnhandledError = Error & {
[digestSym]: 'NEXT_UNHANDLED_ERROR'
[consoleTypeSym]: 'string' | 'error'
}

export function createUnhandledError(message: string): UnhandledError {
const error = new Error(message) as UnhandledError
error.digest = 'NEXT_UNHANDLED_ERROR'
export function createUnhandledError(message: string | Error): UnhandledError {
const error = (
typeof message === 'string' ? new Error(message) : message
) as UnhandledError
error[digestSym] = 'NEXT_UNHANDLED_ERROR'
error[consoleTypeSym] = typeof message === 'string' ? 'string' : 'error'
return error
}

export const isUnhandledConsoleOrRejection = (
error: any
): error is UnhandledError => {
return error && error.digest === 'NEXT_UNHANDLED_ERROR'
return error && error[digestSym] === 'NEXT_UNHANDLED_ERROR'
}

export const getUnhandledErrorType = (error: UnhandledError) => {
return error[consoleTypeSym]
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,20 @@ const rejectionHandlers: Array<ErrorHandler> = []

export function handleClientError(
originError: unknown,
consoleErrorArgs: any[]
consoleErrorArgs: any[],
capturedFromConsole: boolean = false
) {
let error: Error
if (!originError || !isError(originError)) {
// If it's not an error, format the args into an error
const formattedErrorMessage = formatConsoleArgs(consoleErrorArgs)
error = getReactStitchedError(createUnhandledError(formattedErrorMessage))
error = createUnhandledError(formattedErrorMessage)
} else {
error = originError
error = capturedFromConsole
? createUnhandledError(originError)
: originError
}
error = getReactStitchedError(error)

storeHydrationErrorStateFromConsoleArgs(...consoleErrorArgs)
attachHydrationErrorState(error)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,12 +234,12 @@ describe('app-dir - capture-console-error-owner-stack', () => {
"callStacks": "",
"count": 1,
"description": "Error: page error",
"source": "app/ssr-error-instance/page.js (4:11) @ Page
"source": "app/ssr-error-instance/page.js (4:17) @ Page
2 |
3 | export default function Page() {
> 4 | console.error(new Error('page error'))
| ^
| ^
5 | return <p>ssr</p>
6 | }
7 |",
Expand All @@ -252,12 +252,12 @@ describe('app-dir - capture-console-error-owner-stack', () => {
"callStacks": "",
"count": 1,
"description": "Error: page error",
"source": "app/ssr-error-instance/page.js (4:11) @ error
"source": "app/ssr-error-instance/page.js (4:17) @ Page
2 |
3 | export default function Page() {
> 4 | console.error(new Error('page error'))
| ^
| ^
5 | return <p>ssr</p>
6 | }
7 |",
Expand Down Expand Up @@ -289,7 +289,7 @@ describe('app-dir - capture-console-error-owner-stack', () => {
3 | return <p>rsc</p>
4 | }
5 |",
"title": "Unhandled Runtime Error",
"title": "Console Error",
}
`)
} else {
Expand All @@ -306,7 +306,7 @@ describe('app-dir - capture-console-error-owner-stack', () => {
3 | return <p>rsc</p>
4 | }
5 |",
"title": "Unhandled Runtime Error",
"title": "Console Error",
}
`)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ describe('app-dir - capture-console-error', () => {
8 | }}
9 | >
10 | click to error",
"title": "Console Error",
}
`)
}
Expand Down Expand Up @@ -125,6 +126,7 @@ describe('app-dir - capture-console-error', () => {
5 | return <p>render</p>
6 | }
7 |",
"title": "Console Error",
}
`)
}
Expand Down Expand Up @@ -171,6 +173,7 @@ describe('app-dir - capture-console-error', () => {
5 | return <p>render</p>
6 | }
7 |",
"title": "Console Error",
}
`)
}
Expand Down Expand Up @@ -217,6 +220,7 @@ describe('app-dir - capture-console-error', () => {
5 | 'ssr console error:' + (typeof window === 'undefined' ? 'server' : 'client')
6 | )
7 | return <p>ssr</p>",
"title": "Console Error",
}
`)
}
Expand All @@ -236,12 +240,12 @@ describe('app-dir - capture-console-error', () => {
"callStacks": "",
"count": 2,
"description": "Error: page error",
"source": "app/ssr-error-instance/page.js (4:11) @ Page
"source": "app/ssr-error-instance/page.js (4:17) @ Page
2 |
3 | export default function Page() {
> 4 | console.error(new Error('page error'))
| ^
| ^
5 | return <p>ssr</p>
6 | }
7 |",
Expand All @@ -253,7 +257,7 @@ describe('app-dir - capture-console-error', () => {
{
"callStacks": "",
"count": 2,
"description": "page error",
"description": "Error: page error",
"source": "app/ssr-error-instance/page.js (4:17) @ Page
2 |
Expand All @@ -263,6 +267,7 @@ describe('app-dir - capture-console-error', () => {
5 | return <p>ssr</p>
6 | }
7 |",
"title": "Console Error",
}
`)
}
Expand Down Expand Up @@ -290,15 +295,15 @@ describe('app-dir - capture-console-error', () => {
3 | return <p>rsc</p>
4 | }
5 |",
"title": "Unhandled Runtime Error",
"title": "Console Error",
}
`)
} else {
expect(result).toMatchInlineSnapshot(`
{
"callStacks": "",
"count": 1,
"description": "[ Server ] boom",
"description": "[ Server ] Error: boom",
"source": "app/rsc/page.js (2:17) @ Page
1 | export default function Page() {
Expand All @@ -307,6 +312,7 @@ describe('app-dir - capture-console-error', () => {
3 | return <p>rsc</p>
4 | }
5 |",
"title": "Console Error",
}
`)
}
Expand Down

0 comments on commit beb2b74

Please sign in to comment.