diff --git a/docs/02-app/01-building-your-application/01-routing/03-linking-and-navigating.mdx b/docs/02-app/01-building-your-application/01-routing/03-linking-and-navigating.mdx index 747a0e75b8096..de1371182c193 100644 --- a/docs/02-app/01-building-your-application/01-routing/03-linking-and-navigating.mdx +++ b/docs/02-app/01-building-your-application/01-routing/03-linking-and-navigating.mdx @@ -188,7 +188,7 @@ For a full list of `useRouter` methods, see the [API reference](/docs/app/api-re Next.js allows you to use the native [`window.history.pushState`](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState) and [`window.history.replaceState`](https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState) methods to update the browser's history stack without reloading the page. -This behavior is enabled with the Next.js [`windowHistorySupport`](/docs/app/api-reference/next-config-js/windowHistorySupport) config option. When the flag is set to `true`, `pushState` and `replaceState` calls integrate into the Next.js Router, allowing you to sync with [`usePathname`](/docs/app/api-reference/functions/use-pathname) and [`useSearchParams`](/docs/app/api-reference/functions/use-search-params). +`pushState` and `replaceState` calls integrate into the Next.js Router, allowing you to sync with [`usePathname`](/docs/app/api-reference/functions/use-pathname) and [`useSearchParams`](/docs/app/api-reference/functions/use-search-params). ### `window.history.pushState` diff --git a/docs/02-app/02-api-reference/05-next-config-js/windowHistorySupport.mdx b/docs/02-app/02-api-reference/05-next-config-js/windowHistorySupport.mdx deleted file mode 100644 index 6455122f3f827..0000000000000 --- a/docs/02-app/02-api-reference/05-next-config-js/windowHistorySupport.mdx +++ /dev/null @@ -1,20 +0,0 @@ ---- -title: windowHistorySupport -description: Learn how to use the windowHistorySupport option to sync the native History API with the Next.js Router. ---- - -`windowHistorySupport` is an experimental flag that allows you manually call [`window.history.pushState`](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState) and [`window.history.replaceState`](https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState). - -When the flag is enabled, `pushState` and `replaceState` calls are integrated into the Next.js Router, allowing you to sync with [`usePathname`](/docs/app/api-reference/functions/use-pathname) and [`useSearchParams`](/docs/app/api-reference/functions/use-search-params). - -To use it, set `windowHistorySupport` to `true` in your `next.config.js` file: - -```js fileName="next.config.js" -module.exports = { - experimental: { - windowHistorySupport: true, - }, -} -``` - -See the [Linking and Navigation](/docs/app/building-your-application/routing/linking-and-navigating#using-the-native-history-api) documentation for examples. diff --git a/packages/next/src/build/webpack/plugins/define-env-plugin.ts b/packages/next/src/build/webpack/plugins/define-env-plugin.ts index 54a2609a9a589..ef6aa0631e246 100644 --- a/packages/next/src/build/webpack/plugins/define-env-plugin.ts +++ b/packages/next/src/build/webpack/plugins/define-env-plugin.ts @@ -95,9 +95,6 @@ export function getDefineEnv({ isEdgeServer ? 'edge' : isNodeServer ? 'nodejs' : '' ), 'process.env.NEXT_MINIMAL': JSON.stringify(''), - 'process.env.__NEXT_WINDOW_HISTORY_SUPPORT': JSON.stringify( - config.experimental.windowHistorySupport - ), 'process.env.__NEXT_PPR': JSON.stringify(config.experimental.ppr === true), 'process.env.__NEXT_ACTIONS_DEPLOYMENT_ID': JSON.stringify( config.experimental.useDeploymentIdServerActions diff --git a/packages/next/src/client/components/app-router.tsx b/packages/next/src/client/components/app-router.tsx index c68b799116e32..e096a38f1836b 100644 --- a/packages/next/src/client/components/app-router.tsx +++ b/packages/next/src/client/components/app-router.tsx @@ -122,10 +122,7 @@ function HistoryUpdater({ useInsertionEffect(() => { const { tree, pushRef, canonicalUrl } = appRouterState const historyState = { - ...(process.env.__NEXT_WINDOW_HISTORY_SUPPORT && - pushRef.preserveCustomHistoryState - ? window.history.state - : {}), + ...(pushRef.preserveCustomHistoryState ? window.history.state : {}), // Identifier is shortened intentionally. // __NA is used to identify if the history entry can be handled by the app-router. // __N is used to identify if the history entry can be handled by the old router. @@ -467,65 +464,64 @@ function Router({ const originalReplaceState = window.history.replaceState.bind( window.history ) - if (process.env.__NEXT_WINDOW_HISTORY_SUPPORT) { - // Ensure the canonical URL in the Next.js Router is updated when the URL is changed so that `usePathname` and `useSearchParams` hold the pushed values. - const applyUrlFromHistoryPushReplace = ( - url: string | URL | null | undefined - ) => { - const href = window.location.href - startTransition(() => { - dispatch({ - type: ACTION_RESTORE, - url: new URL(url ?? href, href), - tree: window.history.state.__PRIVATE_NEXTJS_INTERNALS_TREE, - }) - }) - } - - /** - * Patch pushState to ensure external changes to the history are reflected in the Next.js Router. - * Ensures Next.js internal history state is copied to the new history entry. - * Ensures usePathname and useSearchParams hold the newly provided url. - */ - window.history.pushState = function pushState( - data: any, - _unused: string, - url?: string | URL | null - ): void { - // Avoid a loop when Next.js internals trigger pushState/replaceState - if (data?.__NA || data?._N) { - return originalPushState(data, _unused, url) - } - data = copyNextJsInternalHistoryState(data) - if (url) { - applyUrlFromHistoryPushReplace(url) - } + // Ensure the canonical URL in the Next.js Router is updated when the URL is changed so that `usePathname` and `useSearchParams` hold the pushed values. + const applyUrlFromHistoryPushReplace = ( + url: string | URL | null | undefined + ) => { + const href = window.location.href + startTransition(() => { + dispatch({ + type: ACTION_RESTORE, + url: new URL(url ?? href, href), + tree: window.history.state.__PRIVATE_NEXTJS_INTERNALS_TREE, + }) + }) + } + /** + * Patch pushState to ensure external changes to the history are reflected in the Next.js Router. + * Ensures Next.js internal history state is copied to the new history entry. + * Ensures usePathname and useSearchParams hold the newly provided url. + */ + window.history.pushState = function pushState( + data: any, + _unused: string, + url?: string | URL | null + ): void { + // Avoid a loop when Next.js internals trigger pushState/replaceState + if (data?.__NA || data?._N) { return originalPushState(data, _unused, url) } + data = copyNextJsInternalHistoryState(data) - /** - * Patch replaceState to ensure external changes to the history are reflected in the Next.js Router. - * Ensures Next.js internal history state is copied to the new history entry. - * Ensures usePathname and useSearchParams hold the newly provided url. - */ - window.history.replaceState = function replaceState( - data: any, - _unused: string, - url?: string | URL | null - ): void { - // Avoid a loop when Next.js internals trigger pushState/replaceState - if (data?.__NA || data?._N) { - return originalReplaceState(data, _unused, url) - } - data = copyNextJsInternalHistoryState(data) + if (url) { + applyUrlFromHistoryPushReplace(url) + } - if (url) { - applyUrlFromHistoryPushReplace(url) - } + return originalPushState(data, _unused, url) + } + + /** + * Patch replaceState to ensure external changes to the history are reflected in the Next.js Router. + * Ensures Next.js internal history state is copied to the new history entry. + * Ensures usePathname and useSearchParams hold the newly provided url. + */ + window.history.replaceState = function replaceState( + data: any, + _unused: string, + url?: string | URL | null + ): void { + // Avoid a loop when Next.js internals trigger pushState/replaceState + if (data?.__NA || data?._N) { return originalReplaceState(data, _unused, url) } + data = copyNextJsInternalHistoryState(data) + + if (url) { + applyUrlFromHistoryPushReplace(url) + } + return originalReplaceState(data, _unused, url) } /** @@ -560,10 +556,8 @@ function Router({ // Register popstate event to call onPopstate. window.addEventListener('popstate', onPopState) return () => { - if (process.env.__NEXT_WINDOW_HISTORY_SUPPORT) { - window.history.pushState = originalPushState - window.history.replaceState = originalReplaceState - } + window.history.pushState = originalPushState + window.history.replaceState = originalReplaceState window.removeEventListener('popstate', onPopState) } }, [dispatch]) diff --git a/packages/next/src/server/config-schema.ts b/packages/next/src/server/config-schema.ts index fd61fd9e60771..71bb361d9fffb 100644 --- a/packages/next/src/server/config-schema.ts +++ b/packages/next/src/server/config-schema.ts @@ -226,7 +226,6 @@ export const configSchema: zod.ZodType = z.lazy(() => excludeDefaultMomentLocales: z.boolean().optional(), experimental: z .strictObject({ - windowHistorySupport: z.boolean().optional(), appDocumentPreloading: z.boolean().optional(), adjustFontFallbacks: z.boolean().optional(), adjustFontFallbacksWithSizeAdjust: z.boolean().optional(), diff --git a/packages/next/src/server/config-shared.ts b/packages/next/src/server/config-shared.ts index b98bb57bacfc7..a2fc74d440384 100644 --- a/packages/next/src/server/config-shared.ts +++ b/packages/next/src/server/config-shared.ts @@ -159,7 +159,6 @@ export interface NextJsWebpackConfig { } export interface ExperimentalConfig { - windowHistorySupport?: boolean caseSensitiveRoutes?: boolean useDeploymentId?: boolean useDeploymentIdServerActions?: boolean @@ -780,7 +779,6 @@ export const defaultConfig: NextConfig = { output: !!process.env.NEXT_PRIVATE_STANDALONE ? 'standalone' : undefined, modularizeImports: undefined, experimental: { - windowHistorySupport: false, serverMinification: true, serverSourceMaps: false, caseSensitiveRoutes: false, diff --git a/test/e2e/app-dir/shallow-routing/next.config.js b/test/e2e/app-dir/shallow-routing/next.config.js index 37432f95db415..807126e4cf0bf 100644 --- a/test/e2e/app-dir/shallow-routing/next.config.js +++ b/test/e2e/app-dir/shallow-routing/next.config.js @@ -1,10 +1,6 @@ /** * @type {import('next').NextConfig} */ -const nextConfig = { - experimental: { - windowHistorySupport: true, - }, -} +const nextConfig = {} module.exports = nextConfig