next.js
797fecb0 - Add experimental support for history.pushState and history.replaceState (#58335)

Commit
2 years ago
Add experimental support for history.pushState and history.replaceState (#58335) ## What? This PR introduces support for manually calling `history.pushState` and `history.replaceState`. It's currently under an experimental flag: ```js /** * @type {import('next').NextConfig} */ const nextConfig = { experimental: { windowHistorySupport: true, }, } module.exports = nextConfig ``` Going forward I'll refer to `history.pushState` as `replaceState` is interchangable. When the flag is enabled you're able to call the web platform `history.pushState` in the usual way: ```js const data = { foo: 'bar' } const url = '/my-new-url?search=tim' window.history.pushState(data, '', url) ``` Let's start by explaining what would happen without the flag: When a new history entry is pushed outside of the Next.js router any back navigation to that history entry will cause a browser reload as it can no longer be used by Next.js as the required metadata for the router is missing. In practice this makes it so that pushState/replaceState is not feasible to be used. Any pathname / searchParams added can't be observed by `usePathname` / `useSearchParams` either. With the flag enabled the pushState/replaceState calls are instrumented and is synced into the Next.js router. This way the Next.js router's internal metadata is preserved, making back navigations apply still, and pathname / searchParams is synced as well, making sure that you can observe it using `usePathname` and `useSearchParams`. ## How? - Added a new experimental flag `windowHistorySupport` - Instruments `history.pushState` and `history.replaceState` - Triggers the same action as popstate (ACTION_RESTORE) to sync the provided url (if provided) into the Next.js router - Copies the Next.js values kept in history.state so that they are not lost - Calls the original pushState/replaceState ~~Something to figure out is how we handle additional pushes/replaces in Next.js as that should override the history state that was previously set.~~ Went with this after discussing with @sebmarkbage: - When you open a page it preserves the custom history state - This is to solve this case: when you manually `window.history.pushState` / `window.history.replaceState` and then do an mpa navigation (i.e. `<a>` or `window.location.href`) and the navigate backwards the custom history state is preserved - When you navigate back and forward (popstate) it preserves the custom history state - When you navigate client-side (i.e. `router.push()` / `<Link>`) the custom history state is not preserved
Author
Parents
Loading