rsnext/packages/next/client/components/react-dev-overlay/internal/ReactDevOverlay.tsx
Hannes Bornö 974e8b61c7
Move root layout validation (#41338)
Moves where the validation is made to make sure the error reaches the
client. Tests that an error overlay is shown on the client.

## Bug

- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have a helpful link attached, see `contributing.md`

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the
feature request has been accepted for implementation before opening a
PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have a helpful link attached, see `contributing.md`

## Documentation / Examples

- [ ] Make sure the linting passes by running `pnpm lint`
- [ ] The "examples guidelines" are followed from [our contributing
doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md)

Co-authored-by: JJ Kasper <jj@jjsweb.site>
2022-10-14 13:55:09 -07:00

90 lines
2.4 KiB
TypeScript

import * as React from 'react'
import {
ACTION_UNHANDLED_ERROR,
OverlayState,
UnhandledErrorAction,
} from './error-overlay-reducer'
import { ShadowPortal } from './components/ShadowPortal'
import { BuildError } from './container/BuildError'
import { Errors, SupportedErrorEvent } from './container/Errors'
import { Base } from './styles/Base'
import { ComponentStyles } from './styles/ComponentStyles'
import { CssReset } from './styles/CssReset'
import { parseStack } from './helpers/parseStack'
import { RootLayoutError } from './container/RootLayoutError'
interface ReactDevOverlayState {
reactError: SupportedErrorEvent | null
}
class ReactDevOverlay extends React.PureComponent<
{
state: OverlayState
children: React.ReactNode
},
ReactDevOverlayState
> {
state = { reactError: null }
static getDerivedStateFromError(error: Error): ReactDevOverlayState {
const e = error
const event: UnhandledErrorAction = {
type: ACTION_UNHANDLED_ERROR,
reason: error,
frames: parseStack(e.stack!),
}
const errorEvent: SupportedErrorEvent = {
id: 0,
event,
}
return { reactError: errorEvent }
}
render() {
const { state, children } = this.props
const { reactError } = this.state
const hasBuildError = state.buildError != null
const hasRuntimeErrors = Boolean(state.errors.length)
const rootLayoutMissingTagsError = state.rootLayoutMissingTagsError
const isMounted =
hasBuildError ||
hasRuntimeErrors ||
reactError ||
rootLayoutMissingTagsError
return (
<>
{reactError ? (
<html>
<head></head>
<body></body>
</html>
) : (
children
)}
{isMounted ? (
<ShadowPortal>
<CssReset />
<Base />
<ComponentStyles />
{rootLayoutMissingTagsError ? (
<RootLayoutError
missingTags={rootLayoutMissingTagsError.missingTags}
/>
) : hasBuildError ? (
<BuildError message={state.buildError!} />
) : hasRuntimeErrors ? (
<Errors errors={state.errors} />
) : reactError ? (
<Errors errors={[reactError]} />
) : undefined}
</ShadowPortal>
) : undefined}
</>
)
}
}
export default ReactDevOverlay