Skip to content

Commit 755a5a2

Browse files
committed
[dev-overlay] Inject isRecoverableError implementation
Same as with `get*Stack` implementations. `isRecoverableError` relies on module scope so it needs to live in the same layer as the setter.
1 parent 562728e commit 755a5a2

File tree

10 files changed

+40
-10
lines changed

10 files changed

+40
-10
lines changed

packages/next/src/client/components/react-dev-overlay/app/hot-reloader-client.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import reportHmrLatency from '../utils/report-hmr-latency'
4545
import { TurbopackHmr } from '../utils/turbopack-hot-reloader-common'
4646
import { NEXT_HMR_REFRESH_HASH_COOKIE } from '../../app-router-headers'
4747
import { getComponentStack, getOwnerStack } from '../../errors/stitched-error'
48+
import { isRecoverableError } from '../../../react-client-callbacks/on-recoverable-error'
4849

4950
export interface Dispatcher {
5051
onBuildOk(): void
@@ -483,7 +484,8 @@ export default function HotReload({
483484
const [state, dispatch] = useErrorOverlayReducer(
484485
'app',
485486
getComponentStack,
486-
getOwnerStack
487+
getOwnerStack,
488+
isRecoverableError
487489
)
488490

489491
const dispatcher = useMemo<Dispatcher>(() => {

packages/next/src/client/components/react-dev-overlay/pages/hooks.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ import * as Bus from './bus'
33
import { useErrorOverlayReducer } from '../shared'
44
import { Router } from '../../../router'
55
import { getComponentStack, getOwnerStack } from '../../errors/stitched-error'
6+
import { isRecoverableError } from '../../../react-client-callbacks/on-recoverable-error'
67

78
export const usePagesDevOverlay = () => {
89
const [state, dispatch] = useErrorOverlayReducer(
910
'pages',
1011
getComponentStack,
11-
getOwnerStack
12+
getOwnerStack,
13+
isRecoverableError
1214
)
1315

1416
React.useEffect(() => {

packages/next/src/client/components/react-dev-overlay/shared.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type { DebugInfo } from './types'
77
import type { DevIndicatorServerState } from '../../../server/dev/dev-indicator-server-state'
88
import type { HMR_ACTION_TYPES } from '../../../server/dev/hot-reloader-types'
99
import { parseStack } from './utils/parse-stack'
10+
import { isConsoleError } from '../errors/console-error'
1011

1112
type FastRefreshState =
1213
/** No refresh in progress. */
@@ -169,7 +170,8 @@ function getInitialState(
169170
export function useErrorOverlayReducer(
170171
routerType: 'pages' | 'app',
171172
getComponentStack: (error: Error) => string | undefined,
172-
getOwnerStack: (error: Error) => string | null | undefined
173+
getOwnerStack: (error: Error) => string | null | undefined,
174+
isRecoverableError: (error: Error) => boolean
173175
) {
174176
function pushErrorFilterDuplicates(
175177
events: SupportedErrorEvent[],
@@ -188,6 +190,11 @@ export function useErrorOverlayReducer(
188190
error,
189191
frames,
190192
componentStackFrames,
193+
type: isRecoverableError(error)
194+
? 'recoverable'
195+
: isConsoleError(error)
196+
? 'console'
197+
: 'runtime',
191198
}
192199
const pendingEvents = events.filter((event) => {
193200
// Filter out duplicate errors

packages/next/src/client/components/react-dev-overlay/ui/components/errors/error-overlay-nav/error-overlay-nav.stories.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,21 @@ export const Default: Story = {
2121
runtime: true,
2222
error: new Error('First error message'),
2323
frames: () => Promise.resolve([]),
24+
type: 'runtime',
2425
},
2526
{
2627
id: 1,
2728
runtime: true,
2829
error: new Error('Second error message'),
2930
frames: () => Promise.resolve([]),
31+
type: 'runtime',
3032
},
3133
{
3234
id: 2,
3335
runtime: true,
3436
error: new Error('Third error message'),
3537
frames: () => Promise.resolve([]),
38+
type: 'runtime',
3639
},
3740
],
3841
activeIdx: 1,

packages/next/src/client/components/react-dev-overlay/ui/components/errors/error-overlay-pagination/error-overlay-pagination.stories.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react'
22
import { ErrorOverlayPagination } from './error-overlay-pagination'
33
import { withShadowPortal } from '../../../storybook/with-shadow-portal'
44
import { useState } from 'react'
5+
import type { ReadyRuntimeError } from '../../../../utils/get-error-by-type'
56

67
const meta: Meta<typeof ErrorOverlayPagination> = {
78
component: ErrorOverlayPagination,
@@ -15,24 +16,27 @@ export default meta
1516
type Story = StoryObj<typeof ErrorOverlayPagination>
1617

1718
// Mock errors for stories
18-
const mockErrors = [
19+
const mockErrors: ReadyRuntimeError[] = [
1920
{
2021
id: 1,
2122
runtime: true as const,
2223
error: new Error('First error'),
2324
frames: () => Promise.resolve([]),
25+
type: 'runtime',
2426
},
2527
{
2628
id: 2,
2729
runtime: true as const,
2830
error: new Error('Second error'),
2931
frames: () => Promise.resolve([]),
32+
type: 'runtime',
3033
},
3134
{
3235
id: 3,
3336
runtime: true as const,
3437
error: new Error('Third error'),
3538
frames: () => Promise.resolve([]),
39+
type: 'runtime',
3640
},
3741
]
3842

packages/next/src/client/components/react-dev-overlay/ui/container/errors.stories.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ const runtimeErrors: ReadyRuntimeError[] = [
9696
},
9797
...Array(20).fill(ignoredFrame),
9898
]),
99+
type: 'runtime',
99100
},
100101
{
101102
id: 2,
@@ -113,6 +114,7 @@ const runtimeErrors: ReadyRuntimeError[] = [
113114
originalCodeFrame: originalCodeFrame('Second error message'),
114115
},
115116
]),
117+
type: 'runtime',
116118
},
117119
{
118120
id: 3,
@@ -130,6 +132,7 @@ const runtimeErrors: ReadyRuntimeError[] = [
130132
originalCodeFrame: originalCodeFrame('Third error message'),
131133
},
132134
]),
135+
type: 'runtime',
133136
},
134137
{
135138
id: 4,
@@ -147,6 +150,7 @@ const runtimeErrors: ReadyRuntimeError[] = [
147150
originalCodeFrame: originalCodeFrame('typeof window !== undefined'),
148151
},
149152
]),
153+
type: 'runtime',
150154
},
151155
]
152156

@@ -232,6 +236,7 @@ export const WithHydrationWarning: Story = {
232236
},
233237
},
234238
]),
239+
type: 'runtime',
235240
},
236241
],
237242
debugInfo: { devtoolsFrontendUrl: undefined },

packages/next/src/client/components/react-dev-overlay/ui/container/errors.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { RuntimeError } from './runtime-error'
55
import { getErrorSource } from '../../../../../shared/lib/error-source'
66
import { HotlinkedText } from '../components/hot-linked-text'
77
import { PseudoHtmlDiff } from './runtime-error/component-stack-pseudo-html'
8-
import { isConsoleError } from '../../../errors/console-error'
98
import { extractNextErrorCode } from '../../../../../lib/error-telemetry-utils'
109
import {
1110
ErrorOverlayLayout,
@@ -19,7 +18,6 @@ import {
1918
import type { ReadyRuntimeError } from '../../utils/get-error-by-type'
2019
import type { ErrorBaseProps } from '../components/errors/error-overlay/error-overlay'
2120
import { getSquashedHydrationErrorDetails } from '../../pages/hydration-error-state'
22-
import { isRecoverableError } from '../../../../react-client-callbacks/on-recoverable-error'
2321

2422
export interface ErrorsProps extends ErrorBaseProps {
2523
runtimeErrors: ReadyRuntimeError[]
@@ -56,11 +54,14 @@ function GenericErrorDescription({ error }: { error: Error }) {
5654
)
5755
}
5856

59-
function getErrorType(error: Error): ErrorOverlayLayoutProps['errorType'] {
60-
if (isRecoverableError(error)) {
57+
function getErrorTypeLabel(
58+
error: Error,
59+
type: ReadyRuntimeError['type']
60+
): ErrorOverlayLayoutProps['errorType'] {
61+
if (type === 'recoverable') {
6162
return `Recoverable ${error.name}`
6263
}
63-
if (isConsoleError(error)) {
64+
if (type === 'console') {
6465
return `Console ${error.name}`
6566
}
6667
return `Runtime ${error.name}`
@@ -141,7 +142,7 @@ export function Errors({
141142
const isServerError = ['server', 'edge-server'].includes(
142143
getErrorSource(error) || ''
143144
)
144-
const errorType = getErrorType(error)
145+
const errorType = getErrorTypeLabel(error, activeError.type)
145146
// TOOD: May be better to always treat everything past the first blank line as notes
146147
// We're currently only special casing hydration error messages.
147148
const notes = errorDetails.notes

packages/next/src/client/components/react-dev-overlay/ui/container/runtime-error/render-error.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export type SupportedErrorEvent = {
1313
error: Error
1414
frames: StackFrame[]
1515
componentStackFrames?: ComponentStackFrame[]
16+
type: 'runtime' | 'recoverable' | 'console'
1617
}
1718

1819
type Props = {

packages/next/src/client/components/react-dev-overlay/ui/dev-overlay.stories.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,20 +52,23 @@ const initialState: OverlayState = {
5252
column: 5,
5353
},
5454
],
55+
type: 'runtime',
5556
},
5657
{
5758
id: 2,
5859
error: Object.assign(new Error('Second error message'), {
5960
__NEXT_ERROR_CODE: 'E002',
6061
}),
6162
frames: [],
63+
type: 'runtime',
6264
},
6365
{
6466
id: 3,
6567
error: Object.assign(new Error('Third error message'), {
6668
__NEXT_ERROR_CODE: 'E003',
6769
}),
6870
frames: [],
71+
type: 'runtime',
6972
},
7073
],
7174
refreshState: { type: 'idle' },

packages/next/src/client/components/react-dev-overlay/utils/get-error-by-type.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export type ReadyRuntimeError = {
1111
error: Error & { environmentName?: string }
1212
frames: OriginalStackFrame[] | (() => Promise<OriginalStackFrame[]>)
1313
componentStackFrames?: ComponentStackFrame[]
14+
type: 'runtime' | 'console' | 'recoverable'
1415
}
1516

1617
export const useFrames = (error: ReadyRuntimeError): OriginalStackFrame[] => {
@@ -43,6 +44,7 @@ export async function getErrorByType(
4344
id: event.id,
4445
runtime: true,
4546
error: event.error,
47+
type: event.type,
4648
} as const
4749

4850
if ('use' in React) {

0 commit comments

Comments
 (0)