Skip to content

Commit 6447d96

Browse files
committed
[dev-overlay] Move replay ssr-only logic outside of AppDevOverlay
This needs to be rendered outside the NDT layer
1 parent 464538b commit 6447d96

File tree

3 files changed

+73
-64
lines changed

3 files changed

+73
-64
lines changed

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

Lines changed: 1 addition & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -5,72 +5,10 @@ import {
55
} from '../shared'
66
import type { GlobalErrorComponent } from '../../global-error'
77

8-
import { useCallback, useEffect } from 'react'
8+
import { useCallback } from 'react'
99
import { AppDevOverlayErrorBoundary } from './app-dev-overlay-error-boundary'
1010
import { FontStyles } from '../font/font-styles'
1111
import { DevOverlay } from '../ui/dev-overlay'
12-
import { handleClientError } from '../../errors/use-error-handler'
13-
import { isNextRouterError } from '../../is-next-router-error'
14-
import { MISSING_ROOT_TAGS_ERROR } from '../../../../shared/lib/errors/constants'
15-
16-
function readSsrError(): (Error & { digest?: string }) | null {
17-
if (typeof document === 'undefined') {
18-
return null
19-
}
20-
21-
const ssrErrorTemplateTag = document.querySelector(
22-
'template[data-next-error-message]'
23-
)
24-
if (ssrErrorTemplateTag) {
25-
const message: string = ssrErrorTemplateTag.getAttribute(
26-
'data-next-error-message'
27-
)!
28-
const stack = ssrErrorTemplateTag.getAttribute('data-next-error-stack')
29-
const digest = ssrErrorTemplateTag.getAttribute('data-next-error-digest')
30-
const error = new Error(message)
31-
if (digest) {
32-
;(error as any).digest = digest
33-
}
34-
// Skip Next.js SSR'd internal errors that which will be handled by the error boundaries.
35-
if (isNextRouterError(error)) {
36-
return null
37-
}
38-
error.stack = stack || ''
39-
return error
40-
}
41-
42-
return null
43-
}
44-
45-
// Needs to be in the same error boundary as the shell.
46-
// If it commits, we know we recovered from an SSR error.
47-
// If it doesn't commit, we errored again and React will take care of error reporting.
48-
function ReplaySsrOnlyErrors({
49-
onBlockingError,
50-
}: {
51-
onBlockingError: () => void
52-
}) {
53-
if (process.env.NODE_ENV !== 'production') {
54-
// Need to read during render. The attributes will be gone after commit.
55-
const ssrError = readSsrError()
56-
// eslint-disable-next-line react-hooks/rules-of-hooks
57-
useEffect(() => {
58-
if (ssrError !== null) {
59-
// TODO(veil): Include original Owner Stack (NDX-905)
60-
// TODO(veil): Mark as recoverable error
61-
// TODO(veil): console.error
62-
handleClientError(ssrError)
63-
64-
// If it's missing root tags, we can't recover, make it blocking.
65-
if (ssrError.digest === MISSING_ROOT_TAGS_ERROR) {
66-
onBlockingError()
67-
}
68-
}
69-
}, [ssrError, onBlockingError])
70-
}
71-
72-
return null
73-
}
7412

7513
function getSquashedHydrationErrorDetails() {
7614
// We don't squash hydration errors in the App Router.
@@ -98,7 +36,6 @@ export function AppDevOverlay({
9836
globalError={globalError}
9937
onError={openOverlay}
10038
>
101-
<ReplaySsrOnlyErrors onBlockingError={openOverlay} />
10239
{children}
10340
</AppDevOverlayErrorBoundary>
10441
<>

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
ACTION_BUILD_OK,
1212
ACTION_DEBUG_INFO,
1313
ACTION_DEV_INDICATOR,
14+
ACTION_ERROR_OVERLAY_OPEN,
1415
ACTION_REFRESH,
1516
ACTION_STATIC_INDICATOR,
1617
ACTION_UNHANDLED_ERROR,
@@ -21,6 +22,7 @@ import {
2122
useErrorOverlayReducer,
2223
} from '../shared'
2324
import { AppDevOverlay } from './app-dev-overlay'
25+
import { ReplaySsrOnlyErrors } from './replay-ssr-only-errors'
2426
import { useErrorHandler } from '../../errors/use-error-handler'
2527
import { RuntimeErrorHandler } from '../../errors/runtime-error-handler'
2628
import {
@@ -58,6 +60,7 @@ export interface Dispatcher {
5860
onDevIndicator(devIndicator: DevIndicatorServerState): void
5961
onUnhandledError(error: Error): void
6062
onUnhandledRejection(error: Error): void
63+
openErrorOverlay(): void
6164
}
6265

6366
let mostRecentCompilationHash: any = null
@@ -529,6 +532,9 @@ export default function HotReload({
529532
reason: error,
530533
})
531534
},
535+
openErrorOverlay() {
536+
dispatch({ type: ACTION_ERROR_OVERLAY_OPEN })
537+
},
532538
}
533539
}, [dispatch])
534540

@@ -618,6 +624,7 @@ export default function HotReload({
618624

619625
return (
620626
<AppDevOverlay state={state} dispatch={dispatch} globalError={globalError}>
627+
<ReplaySsrOnlyErrors onBlockingError={dispatcher.openErrorOverlay} />
621628
{children}
622629
</AppDevOverlay>
623630
)
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { useEffect } from 'react'
2+
import { handleClientError } from '../../errors/use-error-handler'
3+
import { isNextRouterError } from '../../is-next-router-error'
4+
import { MISSING_ROOT_TAGS_ERROR } from '../../../../shared/lib/errors/constants'
5+
6+
function readSsrError(): (Error & { digest?: string }) | null {
7+
if (typeof document === 'undefined') {
8+
return null
9+
}
10+
11+
const ssrErrorTemplateTag = document.querySelector(
12+
'template[data-next-error-message]'
13+
)
14+
if (ssrErrorTemplateTag) {
15+
const message: string = ssrErrorTemplateTag.getAttribute(
16+
'data-next-error-message'
17+
)!
18+
const stack = ssrErrorTemplateTag.getAttribute('data-next-error-stack')
19+
const digest = ssrErrorTemplateTag.getAttribute('data-next-error-digest')
20+
const error = new Error(message)
21+
if (digest) {
22+
;(error as any).digest = digest
23+
}
24+
// Skip Next.js SSR'd internal errors that which will be handled by the error boundaries.
25+
if (isNextRouterError(error)) {
26+
return null
27+
}
28+
error.stack = stack || ''
29+
return error
30+
}
31+
32+
return null
33+
}
34+
35+
/**
36+
* Needs to be in the same error boundary as the shell.
37+
* If it commits, we know we recovered from an SSR error.
38+
* If it doesn't commit, we errored again and React will take care of error reporting.
39+
*/
40+
export function ReplaySsrOnlyErrors({
41+
onBlockingError,
42+
}: {
43+
onBlockingError: () => void
44+
}) {
45+
if (process.env.NODE_ENV !== 'production') {
46+
// Need to read during render. The attributes will be gone after commit.
47+
const ssrError = readSsrError()
48+
// eslint-disable-next-line react-hooks/rules-of-hooks
49+
useEffect(() => {
50+
if (ssrError !== null) {
51+
// TODO(veil): Include original Owner Stack (NDX-905)
52+
// TODO(veil): Mark as recoverable error
53+
// TODO(veil): console.error
54+
handleClientError(ssrError)
55+
56+
// If it's missing root tags, we can't recover, make it blocking.
57+
if (ssrError.digest === MISSING_ROOT_TAGS_ERROR) {
58+
onBlockingError()
59+
}
60+
}
61+
}, [ssrError, onBlockingError])
62+
}
63+
64+
return null
65+
}

0 commit comments

Comments
 (0)