diff --git a/packages/next/src/client/dev/hot-middleware-client.ts b/packages/next/src/client/dev/hot-middleware-client.ts index 508e672f362ed..582d203a219c3 100644 --- a/packages/next/src/client/dev/hot-middleware-client.ts +++ b/packages/next/src/client/dev/hot-middleware-client.ts @@ -1,6 +1,23 @@ +import type { + NextRouter, + PrivateRouteInfo, +} from '../../shared/lib/router/router' import connect from '../components/react-dev-overlay/pages/hot-reloader-client' import { sendMessage } from '../components/react-dev-overlay/pages/websocket' +// Define a local type for the window.next object +interface NextWindow { + next?: { + router?: NextRouter & { + components: { [pathname: string]: PrivateRouteInfo } + } + } + __nextDevClientId?: string + location: Location +} + +declare const window: NextWindow + let reloading = false export default (mode: 'webpack' | 'turbopack') => { @@ -8,11 +25,13 @@ export default (mode: 'webpack' | 'turbopack') => { devClient.subscribeToHmrEvent((obj: any) => { if (reloading) return - // if we're on an error/404 page, we can't reliably tell if the newly added/removed page - // matches the current path. In that case, assume any added/removed entries should trigger a reload of the current page + + // Retrieve the router if it's available + const router = window.next?.router + + // Determine if we're on an error page or the router is not initialized const isOnErrorPage = - window.next.router.pathname === '/404' || - window.next.router.pathname === '/_error' + !router || router.pathname === '/404' || router.pathname === '/_error' switch (obj.action) { case 'reloadPage': { @@ -27,7 +46,13 @@ export default (mode: 'webpack' | 'turbopack') => { } case 'removedPage': { const [page] = obj.data - if (page === window.next.router.pathname || isOnErrorPage) { + + // Check if the removed page is the current page + const isCurrentPage = page === router?.pathname + + // We enter here if the removed page is currently being viewed + // or if we happen to be on an error page. + if (isCurrentPage || isOnErrorPage) { sendMessage( JSON.stringify({ event: 'client-removed-page', @@ -41,11 +66,17 @@ export default (mode: 'webpack' | 'turbopack') => { } case 'addedPage': { const [page] = obj.data - if ( - (page === window.next.router.pathname && - typeof window.next.router.components[page] === 'undefined') || - isOnErrorPage - ) { + + // Check if the added page is the current page + const isCurrentPage = page === router?.pathname + + // Check if the page component is not yet loaded + const isPageNotLoaded = + typeof router?.components?.[page] === 'undefined' + + // We enter this block if the newly added page is the one currently being viewed + // but hasn't been loaded yet, or if we're on an error page. + if ((isCurrentPage && isPageNotLoaded) || isOnErrorPage) { sendMessage( JSON.stringify({ event: 'client-added-page',