diff --git a/packages/next/src/client/components/react-dev-overlay/app/app-dev-overlay.tsx b/packages/next/src/client/components/react-dev-overlay/app/app-dev-overlay.tsx
index 80110ed2b045..cd283fc724d9 100644
--- a/packages/next/src/client/components/react-dev-overlay/app/app-dev-overlay.tsx
+++ b/packages/next/src/client/components/react-dev-overlay/app/app-dev-overlay.tsx
@@ -5,72 +5,10 @@ import {
} from '../shared'
import type { GlobalErrorComponent } from '../../global-error'
-import { useCallback, useEffect } from 'react'
+import { useCallback } from 'react'
import { AppDevOverlayErrorBoundary } from './app-dev-overlay-error-boundary'
import { FontStyles } from '../font/font-styles'
import { DevOverlay } from '../ui/dev-overlay'
-import { handleClientError } from '../../errors/use-error-handler'
-import { isNextRouterError } from '../../is-next-router-error'
-import { MISSING_ROOT_TAGS_ERROR } from '../../../../shared/lib/errors/constants'
-
-function readSsrError(): (Error & { digest?: string }) | null {
- if (typeof document === 'undefined') {
- return null
- }
-
- const ssrErrorTemplateTag = document.querySelector(
- 'template[data-next-error-message]'
- )
- if (ssrErrorTemplateTag) {
- const message: string = ssrErrorTemplateTag.getAttribute(
- 'data-next-error-message'
- )!
- const stack = ssrErrorTemplateTag.getAttribute('data-next-error-stack')
- const digest = ssrErrorTemplateTag.getAttribute('data-next-error-digest')
- const error = new Error(message)
- if (digest) {
- ;(error as any).digest = digest
- }
- // Skip Next.js SSR'd internal errors that which will be handled by the error boundaries.
- if (isNextRouterError(error)) {
- return null
- }
- error.stack = stack || ''
- return error
- }
-
- return null
-}
-
-// Needs to be in the same error boundary as the shell.
-// If it commits, we know we recovered from an SSR error.
-// If it doesn't commit, we errored again and React will take care of error reporting.
-function ReplaySsrOnlyErrors({
- onBlockingError,
-}: {
- onBlockingError: () => void
-}) {
- if (process.env.NODE_ENV !== 'production') {
- // Need to read during render. The attributes will be gone after commit.
- const ssrError = readSsrError()
- // eslint-disable-next-line react-hooks/rules-of-hooks
- useEffect(() => {
- if (ssrError !== null) {
- // TODO(veil): Include original Owner Stack (NDX-905)
- // TODO(veil): Mark as recoverable error
- // TODO(veil): console.error
- handleClientError(ssrError)
-
- // If it's missing root tags, we can't recover, make it blocking.
- if (ssrError.digest === MISSING_ROOT_TAGS_ERROR) {
- onBlockingError()
- }
- }
- }, [ssrError, onBlockingError])
- }
-
- return null
-}
function getSquashedHydrationErrorDetails() {
// We don't squash hydration errors in the App Router.
@@ -98,7 +36,6 @@ export function AppDevOverlay({
globalError={globalError}
onError={openOverlay}
>
-
{children}
<>
diff --git a/packages/next/src/client/components/react-dev-overlay/app/hot-reloader-client.tsx b/packages/next/src/client/components/react-dev-overlay/app/hot-reloader-client.tsx
index f8d2de191e1f..ad2778cca125 100644
--- a/packages/next/src/client/components/react-dev-overlay/app/hot-reloader-client.tsx
+++ b/packages/next/src/client/components/react-dev-overlay/app/hot-reloader-client.tsx
@@ -11,6 +11,7 @@ import {
ACTION_BUILD_OK,
ACTION_DEBUG_INFO,
ACTION_DEV_INDICATOR,
+ ACTION_ERROR_OVERLAY_OPEN,
ACTION_REFRESH,
ACTION_STATIC_INDICATOR,
ACTION_UNHANDLED_ERROR,
@@ -21,6 +22,7 @@ import {
useErrorOverlayReducer,
} from '../shared'
import { AppDevOverlay } from './app-dev-overlay'
+import { ReplaySsrOnlyErrors } from './replay-ssr-only-errors'
import { useErrorHandler } from '../../errors/use-error-handler'
import { RuntimeErrorHandler } from '../../errors/runtime-error-handler'
import {
@@ -58,6 +60,7 @@ export interface Dispatcher {
onDevIndicator(devIndicator: DevIndicatorServerState): void
onUnhandledError(error: Error): void
onUnhandledRejection(error: Error): void
+ openErrorOverlay(): void
}
let mostRecentCompilationHash: any = null
@@ -529,6 +532,9 @@ export default function HotReload({
reason: error,
})
},
+ openErrorOverlay() {
+ dispatch({ type: ACTION_ERROR_OVERLAY_OPEN })
+ },
}
}, [dispatch])
@@ -618,6 +624,7 @@ export default function HotReload({
return (
+
{children}
)
diff --git a/packages/next/src/client/components/react-dev-overlay/app/replay-ssr-only-errors.tsx b/packages/next/src/client/components/react-dev-overlay/app/replay-ssr-only-errors.tsx
new file mode 100644
index 000000000000..bc7196e89b3b
--- /dev/null
+++ b/packages/next/src/client/components/react-dev-overlay/app/replay-ssr-only-errors.tsx
@@ -0,0 +1,65 @@
+import { useEffect } from 'react'
+import { handleClientError } from '../../errors/use-error-handler'
+import { isNextRouterError } from '../../is-next-router-error'
+import { MISSING_ROOT_TAGS_ERROR } from '../../../../shared/lib/errors/constants'
+
+function readSsrError(): (Error & { digest?: string }) | null {
+ if (typeof document === 'undefined') {
+ return null
+ }
+
+ const ssrErrorTemplateTag = document.querySelector(
+ 'template[data-next-error-message]'
+ )
+ if (ssrErrorTemplateTag) {
+ const message: string = ssrErrorTemplateTag.getAttribute(
+ 'data-next-error-message'
+ )!
+ const stack = ssrErrorTemplateTag.getAttribute('data-next-error-stack')
+ const digest = ssrErrorTemplateTag.getAttribute('data-next-error-digest')
+ const error = new Error(message)
+ if (digest) {
+ ;(error as any).digest = digest
+ }
+ // Skip Next.js SSR'd internal errors that which will be handled by the error boundaries.
+ if (isNextRouterError(error)) {
+ return null
+ }
+ error.stack = stack || ''
+ return error
+ }
+
+ return null
+}
+
+/**
+ * Needs to be in the same error boundary as the shell.
+ * If it commits, we know we recovered from an SSR error.
+ * If it doesn't commit, we errored again and React will take care of error reporting.
+ */
+export function ReplaySsrOnlyErrors({
+ onBlockingError,
+}: {
+ onBlockingError: () => void
+}) {
+ if (process.env.NODE_ENV !== 'production') {
+ // Need to read during render. The attributes will be gone after commit.
+ const ssrError = readSsrError()
+ // eslint-disable-next-line react-hooks/rules-of-hooks
+ useEffect(() => {
+ if (ssrError !== null) {
+ // TODO(veil): Include original Owner Stack (NDX-905)
+ // TODO(veil): Mark as recoverable error
+ // TODO(veil): console.error
+ handleClientError(ssrError)
+
+ // If it's missing root tags, we can't recover, make it blocking.
+ if (ssrError.digest === MISSING_ROOT_TAGS_ERROR) {
+ onBlockingError()
+ }
+ }
+ }, [ssrError, onBlockingError])
+ }
+
+ return null
+}