diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/error-overlay/error-overlay.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/error-overlay/error-overlay.tsx index 3cb7574bc8f..022287f10a9 100644 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/error-overlay/error-overlay.tsx +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/error-overlay/error-overlay.tsx @@ -39,7 +39,7 @@ export function ErrorOverlay({ } // No Runtime Errors. - if (!state.errors.length) { + if (!readyErrors.length) { return null } @@ -50,9 +50,7 @@ export function ErrorOverlay({ return ( { diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/errors.stories.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/errors.stories.tsx index c65058931d2..f0c497817f9 100644 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/errors.stories.tsx +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/errors.stories.tsx @@ -1,10 +1,8 @@ import type { Meta, StoryObj } from '@storybook/react' -import type { SupportedErrorEvent } from '../../../internal/container/Errors' import type { ReadyRuntimeError } from '../helpers/get-error-by-type' import { Errors } from './errors' import { withShadowPortal } from '../storybook/with-shadow-portal' -import { ACTION_UNHANDLED_ERROR } from '../../../shared' const meta: Meta = { component: Errors, @@ -17,86 +15,108 @@ const meta: Meta = { export default meta type Story = StoryObj -const errors: SupportedErrorEvent[] = [ +const originalCodeFrame = (message: string) => { + return `\u001b[0m \u001b[90m 1 \u001b[39m \u001b[36mexport\u001b[39m \u001b[36mdefault\u001b[39m \u001b[36mfunction\u001b[39m \u001b[33mHome\u001b[39m() {\u001b[0m +\u001b[0m\u001b[31m\u001b[1m>\u001b[22m\u001b[39m\u001b[90m 2 \u001b[39m \u001b[36mthrow\u001b[39m \u001b[36mnew\u001b[39m \u001b[33mError\u001b[39m(\u001b[32m'${message}'\u001b[39m)\u001b[0m +\u001b[0m \u001b[90m \u001b[39m \u001b[31m\u001b[1m^\u001b[22m\u001b[39m\u001b[0m +\u001b[0m \u001b[90m 3 \u001b[39m \u001b[36mreturn\u001b[39m \u001b[33m<\u001b[39m\u001b[33mdiv\u001b[39m\u001b[33m>\u001b[39m\u001b[33mHello\u001b[39m \u001b[33mWorld\u001b[39m\u001b[33m<\u001b[39m\u001b[33m/\u001b[39m\u001b[33mdiv\u001b[39m\u001b[33m>\u001b[39m\u001b[0m +\u001b[0m \u001b[90m 4 \u001b[39m }\u001b[0m +\u001b[0m \u001b[90m 5 \u001b[39m\u001b[0m` +} + +const sourceStackFrame = { + file: 'app/page.tsx', + methodName: 'Home', + arguments: [], + lineNumber: 2, + column: 9, +} + +const originalStackFrame = { + file: 'app/page.tsx', + methodName: 'Home', + arguments: [], + lineNumber: 2, + column: 9, + ignored: false, +} + +const readyErrors: ReadyRuntimeError[] = [ { id: 1, - event: { - type: ACTION_UNHANDLED_ERROR, - reason: Object.assign(new Error('First error message'), { - __NEXT_ERROR_CODE: 'E001', - }), - componentStackFrames: [ - { - file: 'app/page.tsx', - component: 'Home', - lineNumber: 10, - column: 5, - canOpenInEditor: true, - }, - ], - frames: [ - { - file: 'app/page.tsx', - methodName: 'Home', - arguments: [], - lineNumber: 10, - column: 5, - }, - ], - }, + runtime: true, + error: new Error('First error message'), + frames: [ + { + error: true, + reason: 'First error message', + external: false, + ignored: false, + sourceStackFrame, + originalStackFrame, + originalCodeFrame: originalCodeFrame('First error message'), + }, + ], }, { id: 2, - event: { - type: ACTION_UNHANDLED_ERROR, - reason: Object.assign(new Error('Second error message'), { - __NEXT_ERROR_CODE: 'E002', - }), - frames: [], - }, + runtime: true, + error: new Error('Second error message'), + frames: [ + { + error: true, + reason: 'Second error message', + external: false, + ignored: false, + sourceStackFrame, + originalStackFrame, + originalCodeFrame: originalCodeFrame('Second error message'), + }, + ], }, { id: 3, - event: { - type: ACTION_UNHANDLED_ERROR, - reason: Object.assign(new Error('Third error message'), { - __NEXT_ERROR_CODE: 'E003', - }), - frames: [], - }, + runtime: true, + error: new Error('Third error message'), + frames: [ + { + error: true, + reason: 'Third error message', + external: false, + ignored: false, + sourceStackFrame, + originalStackFrame, + originalCodeFrame: originalCodeFrame('Third error message'), + }, + ], }, { id: 4, - event: { - type: ACTION_UNHANDLED_ERROR, - reason: Object.assign(new Error('Fourth error message'), { - __NEXT_ERROR_CODE: 'E004', - }), - frames: [], - }, - }, -] - -const readyErrors: ReadyRuntimeError[] = [ - { - id: 1, runtime: true, - error: errors[0].event.reason, - frames: [], + error: new Error('Fourth error message'), + frames: [ + { + error: true, + reason: 'Fourth error message', + external: false, + ignored: false, + sourceStackFrame, + originalStackFrame, + originalCodeFrame: originalCodeFrame('Fourth error message'), + }, + ], }, ] export const Default: Story = { args: { - errors, readyErrors, versionInfo: { installed: '15.0.0', staleness: 'fresh', }, - hasStaticIndicator: true, - isTurbopack: true, debugInfo: { devtoolsFrontendUrl: undefined }, + isTurbopack: false, onClose: () => {}, }, } @@ -116,44 +136,55 @@ export const Minimized: Story = { export const WithHydrationWarning: Story = { args: { - errors: [ + readyErrors: [ { id: 1, - event: { - type: ACTION_UNHANDLED_ERROR, - reason: Object.assign(new Error('Hydration error'), { - details: { - warning: [ - 'Text content does not match server-rendered HTML: "%s" !== "%s"', - 'Server Content', - 'Client Content', - ], - reactOutputComponentDiff: ` + runtime: true, + error: Object.assign(new Error('Hydration error'), { + details: { + warning: [ + 'Text content does not match server-rendered HTML: "%s" !== "%s"', + 'Server Content', + 'Client Content', + ], + reactOutputComponentDiff: `
-

hello world

+
hello world
`, + }, + componentStackFrames: [ + { + component: 'MyComponent', + file: 'app/page.tsx', + lineNumber: 10, + columnNumber: 5, }, - componentStackFrames: [ - { - component: 'MyComponent', - file: 'app/page.tsx', - lineNumber: 10, - columnNumber: 5, - }, - { - component: 'ParentComponent', - file: 'app/layout.tsx', - lineNumber: 20, - columnNumber: 3, - }, - ], - }), - frames: [], - }, + { + component: 'ParentComponent', + file: 'app/layout.tsx', + lineNumber: 20, + columnNumber: 3, + }, + ], + }), + frames: [ + { + error: true, + reason: 'First error message', + external: false, + ignored: false, + sourceStackFrame: { + file: 'app/page.tsx', + methodName: 'Home', + arguments: [], + lineNumber: 10, + column: 5, + }, + }, + ], }, ], - readyErrors: [], debugInfo: { devtoolsFrontendUrl: undefined }, onClose: () => {}, }, diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/errors.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/errors.tsx index 7be1332d6f8..826077b78f2 100644 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/errors.tsx +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/errors.tsx @@ -18,14 +18,11 @@ import { } from '../../../../errors/console-error' import { extractNextErrorCode } from '../../../../../../lib/error-telemetry-utils' import { ErrorOverlayLayout } from '../components/errors/error-overlay-layout/error-overlay-layout' -import type { SupportedErrorEvent } from './runtime-error/use-error-hook' export type ErrorsProps = { - errors: SupportedErrorEvent[] readyErrors: ReadyRuntimeError[] isTurbopack: boolean versionInfo: VersionInfo - hasStaticIndicator: boolean debugInfo: DebugInfo onClose: () => void } @@ -75,7 +72,6 @@ function ErrorDescription({ } export function Errors({ - errors, readyErrors, debugInfo, versionInfo, @@ -95,8 +91,8 @@ export function Errors({ }, [onClose]) const isLoading = useMemo(() => { - return readyErrors.length < 1 && Boolean(errors.length) - }, [errors.length, readyErrors.length]) + return readyErrors.length < 1 + }, [readyErrors.length]) const [activeIdx, setActiveIndex] = useState(0)