Skip to content

Commit 62bc131

Browse files
authored
[devtools] Make state read-only in types (#82396)
1 parent 373f3e1 commit 62bc131

File tree

14 files changed

+75
-61
lines changed

14 files changed

+75
-61
lines changed

packages/next/src/next-devtools/dev-overlay/components/call-stack/call-stack.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export function CallStack({
1010
ignoredFramesTally,
1111
onToggleIgnoreList,
1212
}: {
13-
frames: OriginalStackFrame[]
13+
frames: readonly OriginalStackFrame[]
1414
isIgnoreListOpen: boolean
1515
ignoredFramesTally: number
1616
onToggleIgnoreList: () => void

packages/next/src/next-devtools/dev-overlay/components/errors/error-overlay-call-stack/error-overlay-call-stack.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useMemo, useState, useRef } from 'react'
33
import { CallStack } from '../../call-stack/call-stack'
44

55
interface CallStackProps {
6-
frames: OriginalStackFrame[]
6+
frames: readonly OriginalStackFrame[]
77
dialogResizerRef: React.RefObject<HTMLDivElement | null>
88
}
99

packages/next/src/next-devtools/dev-overlay/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,20 +21,23 @@ export const Default: Story = {
2121
runtime: true,
2222
error: new Error('First error message'),
2323
frames: () => Promise.resolve([]),
24+
componentStackFrames: undefined,
2425
type: 'runtime',
2526
},
2627
{
2728
id: 1,
2829
runtime: true,
2930
error: new Error('Second error message'),
3031
frames: () => Promise.resolve([]),
32+
componentStackFrames: undefined,
3133
type: 'runtime',
3234
},
3335
{
3436
id: 2,
3537
runtime: true,
3638
error: new Error('Third error message'),
3739
frames: () => Promise.resolve([]),
40+
componentStackFrames: undefined,
3841
type: 'runtime',
3942
},
4043
],

packages/next/src/next-devtools/dev-overlay/components/errors/error-overlay-pagination/error-overlay-pagination.stories.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,23 @@ const mockErrors: ReadyRuntimeError[] = [
2222
runtime: true as const,
2323
error: new Error('First error'),
2424
frames: () => Promise.resolve([]),
25+
componentStackFrames: undefined,
2526
type: 'runtime',
2627
},
2728
{
2829
id: 2,
2930
runtime: true as const,
3031
error: new Error('Second error'),
3132
frames: () => Promise.resolve([]),
33+
componentStackFrames: undefined,
3234
type: 'runtime',
3335
},
3436
{
3537
id: 3,
3638
runtime: true as const,
3739
error: new Error('Third error'),
3840
frames: () => Promise.resolve([]),
41+
componentStackFrames: undefined,
3942
type: 'runtime',
4043
},
4144
]

packages/next/src/next-devtools/dev-overlay/components/errors/error-overlay-toolbar/restart-server-button.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export function usePersistentCacheErrorDetection({
5151
errors,
5252
dispatch,
5353
}: {
54-
errors: SupportedErrorEvent[]
54+
errors: readonly SupportedErrorEvent[]
5555
dispatch: OverlayDispatch
5656
}) {
5757
useEffect(() => {

packages/next/src/next-devtools/dev-overlay/container/errors.stories.tsx

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -70,20 +70,6 @@ export const WithHydrationWarning: Story = {
7070
- <p> hello world and welcome to my amazing website with lots of content hello world and welcome to my amazing website with lots of content </p>
7171
+ <div> hello world and welcome to my amazing website with lots of content hello world and welcome to my amazing website with lots of content </div>`,
7272
},
73-
componentStackFrames: [
74-
{
75-
component: 'MyComponent',
76-
file: 'app/page.tsx',
77-
lineNumber: 10,
78-
columnNumber: 5,
79-
},
80-
{
81-
component: 'ParentComponent',
82-
file: 'app/layout.tsx',
83-
lineNumber: 20,
84-
columnNumber: 3,
85-
},
86-
],
8773
}),
8874
frames: () =>
8975
Promise.resolve([
@@ -103,6 +89,22 @@ export const WithHydrationWarning: Story = {
10389
},
10490
},
10591
]),
92+
componentStackFrames: [
93+
{
94+
component: 'MyComponent',
95+
file: 'app/page.tsx',
96+
line1: 10,
97+
column1: 5,
98+
canOpenInEditor: true,
99+
},
100+
{
101+
component: 'ParentComponent',
102+
file: 'app/layout.tsx',
103+
line1: 20,
104+
column1: 3,
105+
canOpenInEditor: true,
106+
},
107+
],
106108
type: 'runtime',
107109
},
108110
],

packages/next/src/next-devtools/dev-overlay/container/runtime-error/render-error.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import { usePersistentCacheErrorDetection } from '../../components/errors/error-
1212
export type SupportedErrorEvent = {
1313
id: number
1414
error: Error
15-
frames: StackFrame[]
16-
componentStackFrames?: ComponentStackFrame[]
15+
frames: readonly StackFrame[]
16+
componentStackFrames?: readonly ComponentStackFrame[]
1717
type: 'runtime' | 'recoverable' | 'console'
1818
}
1919

packages/next/src/next-devtools/dev-overlay/shared.ts

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -39,41 +39,40 @@ type FastRefreshState =
3939
/** No refresh in progress. */
4040
| { type: 'idle' }
4141
/** The refresh process has been triggered, but the new code has not been executed yet. */
42-
| { type: 'pending'; errors: SupportedErrorEvent[] }
42+
| { type: 'pending'; errors: readonly SupportedErrorEvent[] }
4343

4444
export interface OverlayState {
45-
nextId: number
46-
buildError: string | null
47-
errors: SupportedErrorEvent[]
48-
refreshState: FastRefreshState
49-
versionInfo: VersionInfo
50-
notFound: boolean
51-
buildingIndicator: boolean
52-
renderingIndicator: boolean
53-
staticIndicator: boolean
54-
showIndicator: boolean
55-
disableDevIndicator: boolean
45+
readonly nextId: number
46+
readonly buildError: string | null
47+
readonly errors: readonly SupportedErrorEvent[]
48+
readonly refreshState: FastRefreshState
49+
readonly versionInfo: VersionInfo
50+
readonly notFound: boolean
51+
readonly buildingIndicator: boolean
52+
readonly renderingIndicator: boolean
53+
readonly staticIndicator: boolean
54+
readonly showIndicator: boolean
55+
readonly disableDevIndicator: boolean
5656
/** Whether to show the restart server button in the panel UI. Currently
5757
* only used when Turbopack + Persistent Cache is enabled.
5858
*/
59-
showRestartServerButton: boolean
60-
debugInfo: DebugInfo
61-
routerType: 'pages' | 'app'
59+
readonly showRestartServerButton: boolean
60+
readonly debugInfo: DebugInfo
61+
readonly routerType: 'pages' | 'app'
6262
/** This flag is used to handle the Error Overlay state in the "old" overlay.
6363
* In the DevTools panel, this value will used for the "Error Overlay Mode"
6464
* which is viewing the "Issues Tab" as a fullscreen.
6565
*/
66-
isErrorOverlayOpen: boolean
67-
devToolsPosition: Corners
68-
devToolsPanelPosition: Record<DevtoolsPanelName, Corners>
69-
devToolsPanelSize: Record<
70-
DevtoolsPanelName,
71-
{ width: number; height: number }
66+
readonly isErrorOverlayOpen: boolean
67+
readonly devToolsPosition: Corners
68+
readonly devToolsPanelPosition: Readonly<Record<DevtoolsPanelName, Corners>>
69+
readonly devToolsPanelSize: Readonly<
70+
Record<DevtoolsPanelName, { width: number; height: number }>
7271
>
73-
scale: number
74-
page: string
75-
theme: 'light' | 'dark' | 'system'
76-
hideShortcut: string | null
72+
readonly scale: number
73+
readonly page: string
74+
readonly theme: 'light' | 'dark' | 'system'
75+
readonly hideShortcut: string | null
7776
}
7877
type DevtoolsPanelName = string
7978
export type OverlayDispatch = React.Dispatch<DispatcherEvent>
@@ -325,10 +324,10 @@ export function useErrorOverlayReducer(
325324
isRecoverableError: (error: Error) => boolean
326325
) {
327326
function pushErrorFilterDuplicates(
328-
events: SupportedErrorEvent[],
327+
events: readonly SupportedErrorEvent[],
329328
id: number,
330329
error: Error
331-
): SupportedErrorEvent[] {
330+
): readonly SupportedErrorEvent[] {
332331
const componentStack = getComponentStack(error)
333332
const componentStackFrames =
334333
componentStack === undefined

packages/next/src/next-devtools/dev-overlay/storybook/errors.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ export const runtimeErrors: ReadyRuntimeError[] = [
126126
},
127127
...Array(20).fill(ignoredFrame),
128128
]),
129+
componentStackFrames: undefined,
129130
type: 'runtime',
130131
},
131132
{
@@ -144,6 +145,7 @@ export const runtimeErrors: ReadyRuntimeError[] = [
144145
originalCodeFrame: originalCodeFrame('Second error message'),
145146
},
146147
]),
148+
componentStackFrames: undefined,
147149
type: 'console',
148150
},
149151
{
@@ -162,6 +164,7 @@ export const runtimeErrors: ReadyRuntimeError[] = [
162164
originalCodeFrame: originalCodeFrame('Third error message'),
163165
},
164166
]),
167+
componentStackFrames: undefined,
165168
type: 'recoverable',
166169
},
167170
{
@@ -180,6 +183,7 @@ export const runtimeErrors: ReadyRuntimeError[] = [
180183
originalCodeFrame: originalCodeFrame('typeof window !== undefined'),
181184
},
182185
]),
186+
componentStackFrames: undefined,
183187
type: 'runtime',
184188
},
185189
{
@@ -204,6 +208,7 @@ export const runtimeErrors: ReadyRuntimeError[] = [
204208
originalCodeFrame: originalCodeFrame('Fifth error message'),
205209
},
206210
]),
211+
componentStackFrames: undefined,
207212
type: 'console',
208213
},
209214
{
@@ -222,6 +227,7 @@ export const runtimeErrors: ReadyRuntimeError[] = [
222227
originalCodeFrame: originalCodeFrame('Sixth error message'),
223228
},
224229
]),
230+
componentStackFrames: undefined,
225231
type: 'recoverable',
226232
},
227233
{
@@ -240,6 +246,7 @@ export const runtimeErrors: ReadyRuntimeError[] = [
240246
originalCodeFrame: originalCodeFrame('Sixth error message'),
241247
},
242248
]),
249+
componentStackFrames: undefined,
243250
type: 'runtime',
244251
},
245252
{
@@ -258,6 +265,7 @@ export const runtimeErrors: ReadyRuntimeError[] = [
258265
originalCodeFrame: originalCodeFrame('Eighth error message'),
259266
},
260267
]),
268+
componentStackFrames: undefined,
261269
type: 'runtime',
262270
},
263271
{
@@ -276,6 +284,7 @@ export const runtimeErrors: ReadyRuntimeError[] = [
276284
originalCodeFrame: originalCodeFrame('Ninth error message'),
277285
},
278286
]),
287+
componentStackFrames: undefined,
279288
type: 'runtime',
280289
},
281290
{
@@ -294,6 +303,7 @@ export const runtimeErrors: ReadyRuntimeError[] = [
294303
originalCodeFrame: originalCodeFrame('Tenth error message'),
295304
},
296305
]),
306+
componentStackFrames: undefined,
297307
type: 'runtime',
298308
},
299309
]

packages/next/src/next-devtools/dev-overlay/utils/get-error-by-type.ts

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,16 @@ export type ReadyRuntimeError = {
99
id: number
1010
runtime: true
1111
error: Error & { environmentName?: string }
12-
frames: OriginalStackFrame[] | (() => Promise<OriginalStackFrame[]>)
13-
componentStackFrames?: ComponentStackFrame[]
12+
frames:
13+
| readonly OriginalStackFrame[]
14+
| (() => Promise<readonly OriginalStackFrame[]>)
15+
componentStackFrames: readonly ComponentStackFrame[] | undefined
1416
type: 'runtime' | 'console' | 'recoverable'
1517
}
1618

1719
export const useFrames = (
1820
error: ReadyRuntimeError | null
19-
): OriginalStackFrame[] => {
21+
): readonly OriginalStackFrame[] => {
2022
if (!error) return []
2123

2224
if ('use' in React) {
@@ -28,7 +30,7 @@ export const useFrames = (
2830
)
2931
}
3032

31-
return React.use((frames as () => Promise<OriginalStackFrame[]>)())
33+
return React.use((frames as () => Promise<readonly OriginalStackFrame[]>)())
3234
} else {
3335
if (!Array.isArray(error.frames)) {
3436
throw new Error(
@@ -49,6 +51,7 @@ export async function getErrorByType(
4951
runtime: true,
5052
error: event.error,
5153
type: event.type,
54+
componentStackFrames: event.componentStackFrames,
5255
} as const
5356

5457
if ('use' in React) {
@@ -63,9 +66,6 @@ export async function getErrorByType(
6366
)
6467
}),
6568
}
66-
if (event.componentStackFrames !== undefined) {
67-
readyRuntimeError.componentStackFrames = event.componentStackFrames
68-
}
6969
return readyRuntimeError
7070
} else {
7171
const readyRuntimeError: ReadyRuntimeError = {
@@ -77,9 +77,6 @@ export async function getErrorByType(
7777
isAppDir
7878
),
7979
}
80-
if (event.componentStackFrames !== undefined) {
81-
readyRuntimeError.componentStackFrames = event.componentStackFrames
82-
}
8380
return readyRuntimeError
8481
}
8582
}

0 commit comments

Comments
 (0)