Repository: vercel/next.js
Pull request: Skip writeToBfCache without window

## What?

Skip bfcache handling server-side.

Changed files:
filename: packages/next/src/client/components/segment-cache/bfcache.ts
patch: @@ -25,6 +25,9 @@ const bfcacheMap: CacheMap<BFCacheEntry> = createCacheMap()
 let currentBfCacheVersion = 0
 
 export function invalidateBfCache(): void {
+  if (typeof window === 'undefined') {
+    return
+  }
   currentBfCacheVersion++
 }
 
@@ -36,6 +39,10 @@ export function writeToBFCache(
   head: React.ReactNode,
   prefetchHead: React.ReactNode
 ): void {
+  if (typeof window === 'undefined') {
+    return
+  }
+
   const entry: BFCacheEntry = {
     rsc,
     prefetchRsc,
@@ -75,6 +82,9 @@ export function writeHeadToBFCache(
 export function readFromBFCache(
   varyPath: SegmentVaryPath
 ): BFCacheEntry | null {
+  if (typeof window === 'undefined') {
+    return null
+  }
   const isRevalidation = false
   return getFromCacheMap(
     // During a back/forward navigation, it doesn't matter how stale the data
@@ -92,6 +102,9 @@ export function readFromBFCacheDuringRegularNavigation(
   now: number,
   varyPath: SegmentVaryPath
 ): BFCacheEntry | null {
+  if (typeof window === 'undefined') {
+    return null
+  }
   const isRevalidation = false
   return getFromCacheMap(
     now,

filename: packages/next/src/client/components/use-action-queue.ts
patch: @@ -53,7 +53,9 @@ export function useActionQueue(
   // of the router state that represents the eventual target if/when the gesture
   // completes. Otherwise it returns the canonical state.
   const [state, setGesture] = useOptimistic(canonicalState)
-  setGestureRouterState = setGesture
+  if (typeof window !== 'undefined') {
+    setGestureRouterState = setGesture
+  }
 
   // Because of a known issue that requires to decode Flight streams inside the
   // render phase, we have to be a bit clever and assign the dispatch method to
@@ -62,22 +64,28 @@ export function useActionQueue(
   // Ideally, what we'd do instead is pass the state as a prop to root.render;
   // this is conceptually how we're modeling the app router state, despite the
   // weird implementation details.
+  let nextDispatch: Dispatch<ReducerActions>
+
   if (process.env.NODE_ENV !== 'production') {
     const { useAppDevRenderingIndicator } =
       require('../../next-devtools/userspace/use-app-dev-rendering-indicator') as typeof import('../../next-devtools/userspace/use-app-dev-rendering-indicator')
     // eslint-disable-next-line react-hooks/rules-of-hooks
     const appDevRenderingIndicator = useAppDevRenderingIndicator()
 
-    dispatch = (action: ReducerActions) => {
+    nextDispatch = (action: ReducerActions) => {
       appDevRenderingIndicator(() => {
         actionQueue.dispatch(action, setState)
       })
     }
   } else {
-    dispatch = (action: ReducerActions) =>
+    nextDispatch = (action: ReducerActions) =>
       actionQueue.dispatch(action, setState)
   }
 
+  if (typeof window !== 'undefined') {
+    dispatch = nextDispatch
+  }
+
   // When navigating to a non-prefetched route, then App Router state will be
   // blocked until the server responds. We need to transfer the `_debugInfo`
   // from the underlying Flight response onto the top-level promise that is