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 d667f40701a29..53721a0bbc099 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 @@ -9,13 +9,11 @@ import { ACTION_BEFORE_REFRESH, ACTION_BUILD_ERROR, ACTION_BUILD_OK, - ACTION_DEBUG_INFO, - ACTION_DEV_INDICATOR, + ACTION_DEV_TOOLS, ACTION_REFRESH, ACTION_STATIC_INDICATOR, ACTION_UNHANDLED_ERROR, ACTION_UNHANDLED_REJECTION, - ACTION_VERSION_INFO, REACT_REFRESH_FULL_RELOAD, reportInvalidHmrMessage, useErrorOverlayReducer, @@ -31,14 +29,12 @@ import { useWebsocketPing, } from '../utils/use-websocket' import { parseComponentStack } from '../utils/parse-component-stack' -import type { VersionInfo } from '../../../../server/dev/parse-version-info' import { HMR_ACTIONS_SENT_TO_BROWSER } from '../../../../server/dev/hot-reloader-types' import type { HMR_ACTION_TYPES, TurbopackMsgToBrowser, } from '../../../../server/dev/hot-reloader-types' import { REACT_REFRESH_FULL_RELOAD_FROM_ERROR } from '../shared' -import type { DebugInfo } from '../types' import { useUntrackedPathname } from '../../navigation-untracked' import { getComponentStack, getOwnerStack } from '../../errors/stitched-error' import { handleDevBuildIndicatorHmrEvents } from '../../../dev/dev-build-indicator/internal/handle-dev-build-indicator-hmr-events' @@ -51,12 +47,10 @@ import { NEXT_HMR_REFRESH_HASH_COOKIE } from '../../app-router-headers' export interface Dispatcher { onBuildOk(): void onBuildError(message: string): void - onVersionInfo(versionInfo: VersionInfo): void - onDebugInfo(debugInfo: DebugInfo): void onBeforeRefresh(): void onRefresh(): void onStaticIndicator(status: boolean): void - onDevIndicator(devIndicator: DevToolsServerState['devIndicator']): void + onDevTools(devTools: DevToolsServerState): void } let mostRecentCompilationHash: any = null @@ -316,9 +310,9 @@ function processMessage( const { errors, warnings } = obj // Is undefined when it's a 'built' event - if ('versionInfo' in obj) dispatcher.onVersionInfo(obj.versionInfo) - if ('debug' in obj && obj.debug) dispatcher.onDebugInfo(obj.debug) - if ('devIndicator' in obj) dispatcher.onDevIndicator(obj.devIndicator) + if ('devTools' in obj) { + dispatcher.onDevTools(obj.devTools) + } const hasErrors = Boolean(errors && errors.length) // Compilation with errors (e.g. syntax error or missing modules). @@ -496,20 +490,11 @@ export default function HotReload({ onRefresh() { dispatch({ type: ACTION_REFRESH }) }, - onVersionInfo(versionInfo) { - dispatch({ type: ACTION_VERSION_INFO, versionInfo }) - }, onStaticIndicator(status: boolean) { dispatch({ type: ACTION_STATIC_INDICATOR, staticIndicator: status }) }, - onDebugInfo(debugInfo) { - dispatch({ type: ACTION_DEBUG_INFO, debugInfo }) - }, - onDevIndicator(devIndicator) { - dispatch({ - type: ACTION_DEV_INDICATOR, - devIndicator, - }) + onDevTools(devTools: DevToolsServerState) { + dispatch({ type: ACTION_DEV_TOOLS, devTools }) }, } }, [dispatch]) diff --git a/packages/next/src/client/components/react-dev-overlay/pages/client.ts b/packages/next/src/client/components/react-dev-overlay/pages/client.ts index 6ddcba19e14f7..21c084cb20bf7 100644 --- a/packages/next/src/client/components/react-dev-overlay/pages/client.ts +++ b/packages/next/src/client/components/react-dev-overlay/pages/client.ts @@ -9,14 +9,12 @@ import { ACTION_BEFORE_REFRESH, ACTION_BUILD_ERROR, ACTION_BUILD_OK, - ACTION_DEV_INDICATOR, + ACTION_DEV_TOOLS, ACTION_REFRESH, ACTION_STATIC_INDICATOR, ACTION_UNHANDLED_ERROR, ACTION_UNHANDLED_REJECTION, - ACTION_VERSION_INFO, } from '../shared' -import type { VersionInfo } from '../../../../server/dev/parse-version-info' import { getComponentStack, getOwnerStack } from '../../errors/stitched-error' import type { DevToolsServerState } from '../../../../server/dev/dev-tools-server-state' @@ -118,18 +116,12 @@ export function onBeforeRefresh() { Bus.emit({ type: ACTION_BEFORE_REFRESH }) } -export function onVersionInfo(versionInfo: VersionInfo) { - Bus.emit({ type: ACTION_VERSION_INFO, versionInfo }) -} - export function onStaticIndicator(isStatic: boolean) { Bus.emit({ type: ACTION_STATIC_INDICATOR, staticIndicator: isStatic }) } -export function onDevIndicator( - devIndicator: DevToolsServerState['devIndicator'] -) { - Bus.emit({ type: ACTION_DEV_INDICATOR, devIndicator }) +export function onDevTools(devTools: DevToolsServerState) { + Bus.emit({ type: ACTION_DEV_TOOLS, devTools }) } export { getErrorByType } from '../utils/get-error-by-type' diff --git a/packages/next/src/client/components/react-dev-overlay/pages/hot-reloader-client.ts b/packages/next/src/client/components/react-dev-overlay/pages/hot-reloader-client.ts index dea69706e237e..3ae21bbc11aeb 100644 --- a/packages/next/src/client/components/react-dev-overlay/pages/hot-reloader-client.ts +++ b/packages/next/src/client/components/react-dev-overlay/pages/hot-reloader-client.ts @@ -38,9 +38,8 @@ import { onBuildOk, onBeforeRefresh, onRefresh, - onVersionInfo, + onDevTools, onStaticIndicator, - onDevIndicator, } from './client' import stripAnsi from 'next/dist/compiled/strip-ansi' import { addMessageListener, sendMessage } from './websocket' @@ -287,8 +286,9 @@ function processMessage(obj: HMR_ACTION_TYPES) { const { errors, warnings } = obj // Is undefined when it's a 'built' event - if ('versionInfo' in obj) onVersionInfo(obj.versionInfo) - if ('devIndicator' in obj) onDevIndicator(obj.devIndicator) + if ('devTools' in obj) { + onDevTools(obj.devTools) + } const hasErrors = Boolean(errors && errors.length) if (hasErrors) { diff --git a/packages/next/src/client/components/react-dev-overlay/shared.ts b/packages/next/src/client/components/react-dev-overlay/shared.ts index 5a65fee454f7f..04e2cf1a2c828 100644 --- a/packages/next/src/client/components/react-dev-overlay/shared.ts +++ b/packages/next/src/client/components/react-dev-overlay/shared.ts @@ -15,17 +15,23 @@ type FastRefreshState = /** The refresh process has been triggered, but the new code has not been executed yet. */ | { type: 'pending'; errors: SupportedErrorEvent[] } +export type DevToolsClientState = { + versionInfo: VersionInfo + debugInfo: DebugInfo + devIndicator: { + staticIndicator: boolean + showIndicator: boolean + disableDevIndicator: boolean + } +} + export interface OverlayState { nextId: number buildError: string | null errors: SupportedErrorEvent[] refreshState: FastRefreshState - versionInfo: VersionInfo notFound: boolean - staticIndicator: boolean - showIndicator: boolean - disableDevIndicator: boolean - debugInfo: DebugInfo + devToolsClientState: DevToolsClientState routerType: 'pages' | 'app' } @@ -34,11 +40,9 @@ export const ACTION_BUILD_OK = 'build-ok' export const ACTION_BUILD_ERROR = 'build-error' export const ACTION_BEFORE_REFRESH = 'before-fast-refresh' export const ACTION_REFRESH = 'fast-refresh' -export const ACTION_VERSION_INFO = 'version-info' export const ACTION_UNHANDLED_ERROR = 'unhandled-error' export const ACTION_UNHANDLED_REJECTION = 'unhandled-rejection' -export const ACTION_DEBUG_INFO = 'debug-info' -export const ACTION_DEV_INDICATOR = 'dev-indicator' +export const ACTION_DEV_TOOLS = 'dev-tools' export const STORAGE_KEY_THEME = '__nextjs-dev-tools-theme' export const STORAGE_KEY_POSITION = '__nextjs-dev-tools-position' @@ -75,19 +79,9 @@ export interface UnhandledRejectionAction { frames: StackFrame[] } -export interface DebugInfoAction { - type: typeof ACTION_DEBUG_INFO - debugInfo: any -} - -interface VersionInfoAction { - type: typeof ACTION_VERSION_INFO - versionInfo: VersionInfo -} - -interface DevIndicatorAction { - type: typeof ACTION_DEV_INDICATOR - devIndicator: DevToolsServerState['devIndicator'] +interface DevToolsAction { + type: typeof ACTION_DEV_TOOLS + devTools: DevToolsServerState } export type BusEvent = @@ -97,10 +91,8 @@ export type BusEvent = | FastRefreshAction | UnhandledErrorAction | UnhandledRejectionAction - | VersionInfoAction | StaticIndicatorAction - | DebugInfoAction - | DevIndicatorAction + | DevToolsAction const REACT_ERROR_STACK_BOTTOM_FRAME_REGEX = // 1st group: v8 @@ -141,17 +133,21 @@ export const INITIAL_OVERLAY_STATE: Omit = { buildError: null, errors: [], notFound: false, - staticIndicator: false, - /* + refreshState: { type: 'idle' }, + devToolsClientState: { + versionInfo: { installed: '0.0.0', staleness: 'unknown' }, + debugInfo: { devtoolsFrontendUrl: undefined }, + devIndicator: { + staticIndicator: false, + disableDevIndicator: false, + /* This is set to `true` when we can reliably know whether the indicator is in disabled state or not. Otherwise the surface would flicker because the disabled flag loads from the config. */ - showIndicator: false, - disableDevIndicator: false, - refreshState: { type: 'idle' }, - versionInfo: { installed: '0.0.0', staleness: 'unknown' }, - debugInfo: { devtoolsFrontendUrl: undefined }, + showIndicator: false, + }, + }, } function getInitialState( @@ -166,11 +162,17 @@ function getInitialState( export function useErrorOverlayReducer(routerType: 'pages' | 'app') { return useReducer((state: OverlayState, action: BusEvent): OverlayState => { switch (action.type) { - case ACTION_DEBUG_INFO: { - return { ...state, debugInfo: action.debugInfo } - } case ACTION_STATIC_INDICATOR: { - return { ...state, staticIndicator: action.staticIndicator } + return { + ...state, + devToolsClientState: { + ...state.devToolsClientState, + devIndicator: { + ...state.devToolsClientState.devIndicator, + staticIndicator: action.staticIndicator, + }, + }, + } } case ACTION_BUILD_OK: { return { ...state, buildError: null } @@ -228,15 +230,21 @@ export function useErrorOverlayReducer(routerType: 'pages' | 'app') { return state } } - case ACTION_VERSION_INFO: { - return { ...state, versionInfo: action.versionInfo } - } - case ACTION_DEV_INDICATOR: { + case ACTION_DEV_TOOLS: { return { ...state, - showIndicator: true, - disableDevIndicator: - shouldDisableDevIndicator || !!action.devIndicator.disabledUntil, + devToolsClientState: { + ...state.devToolsClientState, + versionInfo: action.devTools.versionInfo, + debugInfo: action.devTools.debugInfo, + devIndicator: { + ...state.devToolsClientState.devIndicator, + showIndicator: true, + disableDevIndicator: + shouldDisableDevIndicator || + !!action.devTools.devIndicator.disabledUntil, + }, + }, } } default: { diff --git a/packages/next/src/client/components/react-dev-overlay/ui/components/errors/dev-tools-indicator/dev-tools-indicator.stories.tsx b/packages/next/src/client/components/react-dev-overlay/ui/components/errors/dev-tools-indicator/dev-tools-indicator.stories.tsx index 66f1f3d8315e3..b9b45aeaba06f 100644 --- a/packages/next/src/client/components/react-dev-overlay/ui/components/errors/dev-tools-indicator/dev-tools-indicator.stories.tsx +++ b/packages/next/src/client/components/react-dev-overlay/ui/components/errors/dev-tools-indicator/dev-tools-indicator.stories.tsx @@ -50,12 +50,16 @@ const state: OverlayState = { buildError: null, errors: [], refreshState: { type: 'idle' }, - disableDevIndicator: false, - showIndicator: true, - versionInfo: mockVersionInfo, notFound: false, - staticIndicator: true, - debugInfo: { devtoolsFrontendUrl: undefined }, + devToolsClientState: { + versionInfo: mockVersionInfo, + debugInfo: { devtoolsFrontendUrl: undefined }, + devIndicator: { + staticIndicator: true, + showIndicator: true, + disableDevIndicator: false, + }, + }, } export const StaticRoute: Story = { @@ -71,7 +75,13 @@ export const DynamicRoute: Story = { errorCount: 0, state: { ...state, - staticIndicator: false, + devToolsClientState: { + ...state.devToolsClientState, + devIndicator: { + ...state.devToolsClientState.devIndicator, + staticIndicator: false, + }, + }, }, setIsErrorOverlayOpen: () => {}, }, diff --git a/packages/next/src/client/components/react-dev-overlay/ui/components/errors/dev-tools-indicator/dev-tools-indicator.tsx b/packages/next/src/client/components/react-dev-overlay/ui/components/errors/dev-tools-indicator/dev-tools-indicator.tsx index 1763496a708dc..106eb89020dfd 100644 --- a/packages/next/src/client/components/react-dev-overlay/ui/components/errors/dev-tools-indicator/dev-tools-indicator.tsx +++ b/packages/next/src/client/components/react-dev-overlay/ui/components/errors/dev-tools-indicator/dev-tools-indicator.tsx @@ -48,9 +48,9 @@ export function DevToolsIndicator({ return ( { setIsDevToolsIndicatorVisible(false) fetch('/__nextjs_disable_dev_indicator', { @@ -59,7 +59,10 @@ export function DevToolsIndicator({ }} setIsErrorOverlayOpen={setIsErrorOverlayOpen} isTurbopack={!!process.env.TURBOPACK} - disabled={state.disableDevIndicator || !isDevToolsIndicatorVisible} + disabled={ + state.devToolsClientState.devIndicator.disableDevIndicator || + !isDevToolsIndicatorVisible + } isBuildError={isBuildError} {...props} /> diff --git a/packages/next/src/client/components/react-dev-overlay/ui/components/errors/error-overlay/error-overlay.tsx b/packages/next/src/client/components/react-dev-overlay/ui/components/errors/error-overlay/error-overlay.tsx index 468f8a014ca57..67e0ea41b71d7 100644 --- a/packages/next/src/client/components/react-dev-overlay/ui/components/errors/error-overlay/error-overlay.tsx +++ b/packages/next/src/client/components/react-dev-overlay/ui/components/errors/error-overlay/error-overlay.tsx @@ -1,4 +1,4 @@ -import type { OverlayState } from '../../../../shared' +import type { DevToolsClientState, OverlayState } from '../../../../shared' import { Suspense } from 'react' import { BuildError } from '../../../container/build-error' @@ -12,7 +12,7 @@ export interface ErrorBaseProps { rendered: boolean transitionDurationMs: number isTurbopack: boolean - versionInfo: OverlayState['versionInfo'] + versionInfo: DevToolsClientState['versionInfo'] errorCount: number } @@ -40,7 +40,7 @@ export function ErrorOverlay({ rendered, transitionDurationMs, isTurbopack, - versionInfo: state.versionInfo, + versionInfo: state.devToolsClientState.versionInfo, errorCount, } @@ -71,7 +71,7 @@ export function ErrorOverlay({ return ( { setIsErrorOverlayOpen(false) diff --git a/packages/next/src/client/components/react-dev-overlay/ui/dev-overlay.stories.tsx b/packages/next/src/client/components/react-dev-overlay/ui/dev-overlay.stories.tsx index 735cb06313fd6..b488557aa3644 100644 --- a/packages/next/src/client/components/react-dev-overlay/ui/dev-overlay.stories.tsx +++ b/packages/next/src/client/components/react-dev-overlay/ui/dev-overlay.stories.tsx @@ -22,8 +22,18 @@ const state: OverlayState = { nextId: 0, routerType: 'app', buildError: null, - disableDevIndicator: false, - showIndicator: true, + devToolsClientState: { + versionInfo: { + installed: '15.2.0', + staleness: 'fresh', + }, + debugInfo: { devtoolsFrontendUrl: undefined }, + devIndicator: { + staticIndicator: true, + showIndicator: true, + disableDevIndicator: false, + }, + }, errors: [ { id: 1, @@ -75,12 +85,6 @@ const state: OverlayState = { ], refreshState: { type: 'idle' }, notFound: false, - staticIndicator: false, - debugInfo: { devtoolsFrontendUrl: undefined }, - versionInfo: { - installed: '15.2.0', - staleness: 'fresh', - }, } export const Default: Story = { diff --git a/packages/next/src/client/components/react-dev-overlay/ui/dev-overlay.tsx b/packages/next/src/client/components/react-dev-overlay/ui/dev-overlay.tsx index 7b18b0b57f5da..26d6050aa4afc 100644 --- a/packages/next/src/client/components/react-dev-overlay/ui/dev-overlay.tsx +++ b/packages/next/src/client/components/react-dev-overlay/ui/dev-overlay.tsx @@ -36,7 +36,7 @@ export function DevOverlay({ const isBuildError = state.buildError !== null return ( <> - {state.showIndicator && ( + {state.devToolsClientState.devIndicator.showIndicator && ( warnings: ReadonlyArray - versionInfo: VersionInfo updatedModules?: ReadonlyArray - debug?: DebugInfo - devIndicator: DevToolsServerState['devIndicator'] + devTools: { + debugInfo: DebugInfo + versionInfo: VersionInfo + devIndicator: DevToolsServerState['devIndicator'] + } } interface BuiltAction { action: HMR_ACTIONS_SENT_TO_BROWSER.BUILT @@ -124,6 +127,11 @@ export interface DevIndicatorAction { devIndicator: DevToolsServerState } +export interface DevToolsAction { + action: HMR_ACTIONS_SENT_TO_BROWSER.DEV_TOOLS + devTools: DevToolsServerState +} + export type HMR_ACTION_TYPES = | TurbopackMessageAction | TurbopackConnectedAction @@ -141,6 +149,7 @@ export type HMR_ACTION_TYPES = | ServerErrorAction | AppIsrManifestAction | DevIndicatorAction + | DevToolsAction export type TurbopackMsgToBrowser = | { type: HMR_ACTIONS_SENT_TO_BROWSER.TURBOPACK_MESSAGE; data: any }