Skip to content

Commit

Permalink
Remove full reload overlay and warn in CLI instead (#37874)
Browse files Browse the repository at this point in the history
- Always perform a full reload when needed without blocking with the overlay.
- Old client warnings re-added.
- Post client warning to dev server and print it in the CLI. 


## Bug

- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have 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 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.md#adding-examples)
  • Loading branch information
Hannes Bornö authored Jun 22, 2022
1 parent ee89517 commit 2ff660c
Show file tree
Hide file tree
Showing 16 changed files with 140 additions and 285 deletions.
53 changes: 26 additions & 27 deletions packages/next/client/dev/error-overlay/hot-dev-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import {
onBuildError,
onBuildOk,
onRefresh,
onFullRefreshNeeded,
} from 'next/dist/compiled/@next/react-dev-overlay/dist/client'
import stripAnsi from 'next/dist/compiled/strip-ansi'
import { addMessageListener, sendMessage } from './websocket'
Expand Down Expand Up @@ -314,15 +313,23 @@ function tryApplyUpdates(onHotUpdateSuccess) {
function handleApplyUpdates(err, updatedModules) {
if (err || hadRuntimeError || !updatedModules) {
if (err) {
performFullRefresh(err)
console.warn(
'[Fast Refresh] performing full reload\n\n' +
"Fast Refresh will perform a full reload when you edit a file that's imported by modules outside of the React rendering tree.\n" +
'You might have a file which exports a React component but also exports a value that is imported by a non-React component file.\n' +
'Consider migrating the non-React component export to a separate file and importing it into both files.\n\n' +
'It is also possible the parent component of the component you edited is a class component, which disables Fast Refresh.\n' +
'Fast Refresh requires at least one parent function component in your React tree.'
)
} else if (hadRuntimeError) {
performFullRefresh()
console.warn(
'[Fast Refresh] performing full reload because your application had an unrecoverable error'
)
}
performFullReload(err)
return
}

clearFullRefreshStorage()

const hasUpdates = Boolean(updatedModules.length)
if (typeof onHotUpdateSuccess === 'function') {
// Maybe we want to do something.
Expand Down Expand Up @@ -356,27 +363,19 @@ function tryApplyUpdates(onHotUpdateSuccess) {
)
}

const FULL_REFRESH_STORAGE_KEY = '_has_warned_about_full_refresh'

function performFullRefresh(err) {
if (!hasAlreadyWarnedAboutFullRefresh()) {
sessionStorage.setItem(FULL_REFRESH_STORAGE_KEY, 'true')
const reason =
err &&
((err.stack && err.stack.split('\n').slice(0, 5).join('\n')) ||
err.message ||
err + '')
onFullRefreshNeeded(reason)
} else {
window.location.reload()
}
}

function hasAlreadyWarnedAboutFullRefresh() {
return sessionStorage.getItem(FULL_REFRESH_STORAGE_KEY) !== null
}
function performFullReload(err) {
const stackTrace =
err &&
((err.stack && err.stack.split('\n').slice(0, 5).join('\n')) ||
err.message ||
err + '')

sendMessage(
JSON.stringify({
event: 'client-full-reload',
stackTrace,
})
)

function clearFullRefreshStorage() {
if (sessionStorage.getItem(FULL_REFRESH_STORAGE_KEY) !== 'ignore')
sessionStorage.removeItem(FULL_REFRESH_STORAGE_KEY)
window.location.reload()
}
10 changes: 10 additions & 0 deletions packages/next/server/dev/hot-reloader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
runDependingOnPageType,
} from '../../build/entries'
import { watchCompilers } from '../../build/output'
import * as Log from '../../build/output/log'
import getBaseWebpackConfig from '../../build/webpack-config'
import { API_ROUTE, APP_DIR_ALIAS } from '../../lib/constants'
import { recursiveDelete } from '../../lib/recursive-delete'
Expand Down Expand Up @@ -351,6 +352,15 @@ export default class HotReloader {
}
break
}
case 'client-full-reload': {
Log.warn(
'Fast Refresh had to perform a full reload. Read more: https://nextjs.org/docs/basic-features/fast-refresh#how-it-works'
)
if (payload.stackTrace) {
console.warn(payload.stackTrace)
}
break
}
default: {
break
}
Expand Down
13 changes: 1 addition & 12 deletions packages/react-dev-overlay/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,22 +85,11 @@ function onBuildError(message: string) {
Bus.emit({ type: Bus.TYPE_BUILD_ERROR, message })
}

function onFullRefreshNeeded(reason?: string) {
Bus.emit({ type: Bus.TYPE_FULL_REFRESH_NEEDED, reason: reason ?? null })
}

function onRefresh() {
Bus.emit({ type: Bus.TYPE_REFRESH })
}

export { getErrorByType } from './internal/helpers/getErrorByType'
export { getServerError } from './internal/helpers/nodeStackFrames'
export { default as ReactDevOverlay } from './internal/ReactDevOverlay'
export {
onBuildOk,
onBuildError,
onFullRefreshNeeded,
register,
unregister,
onRefresh,
}
export { onBuildOk, onBuildError, register, unregister, onRefresh }
35 changes: 4 additions & 31 deletions packages/react-dev-overlay/src/internal/ReactDevOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import * as Bus from './bus'
import { ShadowPortal } from './components/ShadowPortal'
import { BuildError } from './container/BuildError'
import { Errors, SupportedErrorEvent } from './container/Errors'
import { FullRefreshWarning } from './container/FullRefreshWarning'
import { ErrorBoundary } from './ErrorBoundary'
import { Base } from './styles/Base'
import { ComponentStyles } from './styles/ComponentStyles'
Expand All @@ -14,8 +13,6 @@ type OverlayState = {
nextId: number
buildError: string | null
errors: SupportedErrorEvent[]
fullRefreshReason: string | null
isAboutToFullRefresh: boolean
}

function reducer(state: OverlayState, ev: Bus.BusEvent): OverlayState {
Expand All @@ -26,19 +23,6 @@ function reducer(state: OverlayState, ev: Bus.BusEvent): OverlayState {
case Bus.TYPE_BUILD_ERROR: {
return { ...state, buildError: ev.message }
}
case Bus.TYPE_FULL_REFRESH_NEEDED: {
const aboutToRefreshNewState: OverlayState = {
...state,
fullRefreshReason: null,
isAboutToFullRefresh: true,
}

if (ev.reason === null) {
return aboutToRefreshNewState
}

return { ...aboutToRefreshNewState, fullRefreshReason: ev.reason }
}
case Bus.TYPE_REFRESH: {
return { ...state, buildError: null, errors: [] }
}
Expand All @@ -58,7 +42,7 @@ function reducer(state: OverlayState, ev: Bus.BusEvent): OverlayState {
}
}

type ErrorType = 'runtime' | 'build' | 'full-refresh'
type ErrorType = 'runtime' | 'build'

const ReactDevOverlay: React.FunctionComponent = function ReactDevOverlay({
children,
Expand All @@ -73,8 +57,6 @@ const ReactDevOverlay: React.FunctionComponent = function ReactDevOverlay({
nextId: 1,
buildError: null,
errors: [],
fullRefreshReason: null,
isAboutToFullRefresh: false,
})

React.useEffect(() => {
Expand All @@ -93,9 +75,8 @@ const ReactDevOverlay: React.FunctionComponent = function ReactDevOverlay({

const hasBuildError = state.buildError != null
const hasRuntimeErrors = Boolean(state.errors.length)
const isAboutToFullRefresh = state.isAboutToFullRefresh

const isMounted = hasBuildError || hasRuntimeErrors || isAboutToFullRefresh
const isMounted = hasBuildError || hasRuntimeErrors

return (
<React.Fragment>
Expand All @@ -109,17 +90,9 @@ const ReactDevOverlay: React.FunctionComponent = function ReactDevOverlay({
<ComponentStyles />

{shouldPreventDisplay(
hasBuildError
? 'build'
: hasRuntimeErrors
? 'runtime'
: isAboutToFullRefresh
? 'full-refresh'
: null,
hasBuildError ? 'build' : hasRuntimeErrors ? 'runtime' : null,
preventDisplay
) ? null : isAboutToFullRefresh ? (
<FullRefreshWarning reason={state.fullRefreshReason} />
) : hasBuildError ? (
) ? null : hasBuildError ? (
<BuildError message={state.buildError!} />
) : hasRuntimeErrors ? (
<Errors errors={state.errors} />
Expand Down
6 changes: 0 additions & 6 deletions packages/react-dev-overlay/src/internal/bus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { StackFrame } from 'stacktrace-parser'

export const TYPE_BUILD_OK = 'build-ok'
export const TYPE_BUILD_ERROR = 'build-error'
export const TYPE_FULL_REFRESH_NEEDED = 'full-refresh-needed'
export const TYPE_REFRESH = 'fast-refresh'
export const TYPE_UNHANDLED_ERROR = 'unhandled-error'
export const TYPE_UNHANDLED_REJECTION = 'unhandled-rejection'
Expand All @@ -13,10 +12,6 @@ export type BuildError = {
message: string
}
export type FastRefresh = { type: typeof TYPE_REFRESH }
export type FullRefreshNeeded = {
type: typeof TYPE_FULL_REFRESH_NEEDED
reason: string | null
}
export type UnhandledError = {
type: typeof TYPE_UNHANDLED_ERROR
reason: Error
Expand All @@ -31,7 +26,6 @@ export type BusEvent =
| BuildOk
| BuildError
| FastRefresh
| FullRefreshNeeded
| UnhandledError
| UnhandledRejection

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { styles as terminal } from '../components/Terminal/styles'
import { styles as toast } from '../components/Toast'
import { styles as buildErrorStyles } from '../container/BuildError'
import { styles as containerErrorStyles } from '../container/Errors'
import { styles as fullRefreshWarningStyles } from '../container/FullRefreshWarning'
import { styles as containerRuntimeErrorStyles } from '../container/RuntimeError'
import { noop as css } from '../helpers/noop-template'

Expand All @@ -26,7 +25,6 @@ export function ComponentStyles() {
${buildErrorStyles}
${containerErrorStyles}
${containerRuntimeErrorStyles}
${fullRefreshWarningStyles}
`}
</style>
)
Expand Down
2 changes: 0 additions & 2 deletions test/development/acceptance/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {
ignoreFullRefreshWarnings,
getRedboxDescription,
getRedboxHeader,
getRedboxSource,
Expand Down Expand Up @@ -31,7 +30,6 @@ export async function sandbox(
}
await next.start()
const browser = await webdriver(next.appPort, '/')
await ignoreFullRefreshWarnings(browser)
return {
session: {
async write(filename, content) {
Expand Down
Loading

0 comments on commit 2ff660c

Please sign in to comment.