Skip to content

Conversation

@feedthejim
Copy link
Contributor

@feedthejim feedthejim commented Dec 30, 2025

What

Adds a --experimental-cpu-prof flag to next dev, next build, and next start commands to capture V8 CPU profiles for debugging performance bottlenecks.

Why

When investigating slow builds, slow dev server startups, or production server performance issues, having access to CPU profiles is invaluable. This provides a first-party way to capture these profiles without needing to manually set up the V8 inspector.

How

  • Adds --experimental-cpu-prof flag to CLI commands
  • Uses V8's built-in CPU profiler via Node.js inspector module
  • Profiles are saved to .next/cpu-profiles/ with descriptive filenames
  • Profiles are saved on process exit (Ctrl+C, SIGTERM, or normal exit)

Profile files generated

next dev:

  • dev-main-* - Parent process (dev server orchestration)
  • dev-server-* - Child server process (request handling and rendering)

next build (Turbopack):

  • build-main-* - Main build orchestration process
  • build-turbopack-* - Turbopack compilation worker

next build (Webpack):

  • build-main-* - Main build orchestration process
  • build-webpack-client-* - Client bundle compilation worker
  • build-webpack-server-* - Server bundle compilation worker
  • build-webpack-edge-server-* - Edge runtime compilation worker

next start:

  • start-main-* - Production server process

Changes addressing PR review comments

  • Removed signal handlers from cpu-profile.ts to prevent conflicts with CLI cleanup logic (telemetry, traces, etc.)
  • Added synchronous exit handler for non-signal process exits (errors, process.exit() calls)
  • CLI commands now explicitly call saveCpuProfile() as part of their cleanup before exiting
  • Replaced raw ANSI escape codes with picocolors library
  • Added comprehensive documentation about profile file naming for each command
  • Added build profiling test that verifies correct profile generation for both Turbopack and Webpack modes

Copy link
Contributor Author

feedthejim commented Dec 30, 2025

This stack of pull requests is managed by Graphite. Learn more about stacking.

@nextjs-bot
Copy link
Collaborator

nextjs-bot commented Dec 30, 2025

Tests Passed

@nextjs-bot nextjs-bot added the Documentation Related to Next.js' official documentation. label Dec 30, 2025
Copy link
Contributor

@vercel vercel bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Suggestion:

Signal handler conflict when CPU profiling is enabled in build mode - the process will exit before the CPU profile is saved if the build is interrupted with SIGINT or SIGTERM.

View Details
📝 Patch Details
diff --git a/packages/next/src/cli/next-build.ts b/packages/next/src/cli/next-build.ts
index f453778087..601cb6dae2 100755
--- a/packages/next/src/cli/next-build.ts
+++ b/packages/next/src/cli/next-build.ts
@@ -36,8 +36,13 @@ export type NextBuildOptions = {
 }
 
 const nextBuild = async (options: NextBuildOptions, directory?: string) => {
-  process.on('SIGTERM', () => process.exit(143))
-  process.on('SIGINT', () => process.exit(130))
+  // Only register signal handlers if CPU profiling is not enabled.
+  // If CPU profiling is enabled, cpu-profile.ts already registers signal handlers
+  // that will properly save the CPU profile before exiting.
+  if (!process.env.NEXT_CPU_PROF && !process.env.__NEXT_PRIVATE_CPU_PROFILE) {
+    process.on('SIGTERM', () => process.exit(143))
+    process.on('SIGINT', () => process.exit(130))
+  }
 
   const {
     experimentalAnalyze,

Analysis

Signal handler conflict prevents CPU profile from being saved when build is interrupted

What fails: When next build --experimental-cpu-prof is interrupted with SIGINT or SIGTERM, the CPU profile is never saved to disk despite the --experimental-cpu-prof flag being enabled.

How to reproduce:

# Start a Next.js build with CPU profiling
next build --experimental-cpu-prof

# Wait a moment, then interrupt with Ctrl+C or send SIGTERM
# The build will exit but no .cpuprofile file will be created in .next/cpu-profiles/

What happens: When a SIGINT/SIGTERM signal is received, both signal handlers execute:

  1. Handler from cpu-profile.ts (registered first when module loads) calls async saveCpuProfile().then(() => process.exit(130/143))
  2. Handler from next-build.ts (registered second) immediately calls process.exit(130/143)

Since process.exit() terminates the process synchronously, the async save operation from step 1 never completes, and the CPU profile is never written to disk.

Expected: When CPU profiling is enabled and the process receives a SIGINT/SIGTERM, the CPU profile should be saved before the process exits, just like when the build completes normally.

Root cause: Duplicate signal handler registration. When packages/next/src/cli/next-build.ts is imported, it registers SIGTERM and SIGINT handlers at lines 39-40. However, if CPU profiling is enabled via --experimental-cpu-prof flag, packages/next/src/server/lib/cpu-profile.ts already registered its own handlers for the same signals at module load time (lines 18-23). When both handlers are registered for the same signal, both execute in registration order, with the second one's synchronous process.exit() preventing the first one's async operation from completing.

Fix: Conditionally register signal handlers in next-build.ts only when CPU profiling is disabled. When CPU profiling is enabled, let cpu-profile.ts handle the signals exclusively, as it properly awaits the async save operation before exiting.

Fix on Vercel

@feedthejim feedthejim force-pushed the perf-cpu-profiling branch 2 times, most recently from 4516b6a to 544231c Compare December 30, 2025 16:38
@feedthejim feedthejim changed the base branch from perf-dev-scripts to graphite-base/87946 December 30, 2025 16:45
@feedthejim feedthejim changed the base branch from graphite-base/87946 to perf-stats-improvements December 30, 2025 16:45
@feedthejim feedthejim force-pushed the perf-stats-improvements branch 2 times, most recently from 207d6ce to eee9da7 Compare December 30, 2025 17:00
@feedthejim feedthejim force-pushed the perf-cpu-profiling branch 2 times, most recently from d6201d6 to 0ec8ccc Compare December 30, 2025 17:02
@feedthejim feedthejim force-pushed the perf-stats-improvements branch 2 times, most recently from 44aa30a to d058637 Compare December 30, 2025 17:05
Copy link
Contributor

@vercel vercel bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Suggestions:

  1. Signal handlers registered in next-build.ts will prevent CPU profiles from being saved when the build is interrupted with SIGINT/SIGTERM, because the signal handler exits immediately without waiting for the async profile save to complete.
View Details
📝 Patch Details
diff --git a/packages/next/src/cli/next-build.ts b/packages/next/src/cli/next-build.ts
index f453778087..971c44ab9a 100755
--- a/packages/next/src/cli/next-build.ts
+++ b/packages/next/src/cli/next-build.ts
@@ -36,8 +36,6 @@ export type NextBuildOptions = {
 }
 
 const nextBuild = async (options: NextBuildOptions, directory?: string) => {
-  process.on('SIGTERM', () => process.exit(143))
-  process.on('SIGINT', () => process.exit(130))
 
   const {
     experimentalAnalyze,

Analysis

CPU profile not saved when build interrupted with SIGINT/SIGTERM

What fails: Signal handlers registered in packages/next/src/cli/next-build.ts lines 39-40 prevent CPU profiles from being saved when the build is interrupted with SIGINT or SIGTERM, because the signal handler calls process.exit() immediately without waiting for the async saveCpuProfile() operation to complete.

How to reproduce:

next build --experimental-cpu-prof
# Then press Ctrl+C during the build to send SIGINT

What happens: The process exits immediately and the CPU profile file is not saved to .next/cpu-profiles/. The first registered signal handler (from cpu-profile module) calls saveCpuProfile().then(() => process.exit()), but the second registered handler (from next-build.ts) calls process.exit() synchronously, interrupting the async operation before it completes.

Expected behavior: When the build is interrupted with SIGINT/SIGTERM, the CPU profile should be saved before the process exits, per Node.js EventEmitter documentation which notes that signal handlers are called synchronously in registration order, and per Node.js process.exit() documentation which states that calling process.exit() forces the process to exit immediately before async operations can complete.

Root cause: Multiple signal handlers are registered for the same signal. Node.js calls all registered listeners synchronously in the order they were registered:

  1. cpu-profile.ts registers handlers first (lines 13-18)
  2. next-build.ts registers handlers second (lines 39-40)
  3. When a signal is received, Handler 1 starts async operation but Handler 2's process.exit() prevents completion

Fix: Remove the duplicate signal handlers from next-build.ts lines 39-40. The cpu-profile module's handlers are sufficient for graceful shutdown on SIGINT/SIGTERM. For normal build completion, next.ts line 210 already calls await mod.saveCpuProfile() before exiting.

2. In dev mode\, the cpu\-profile signal handlers in the child process \(dev server\) will race with the start\-server cleanup handlers\, potentially preventing either profiles from being saved or proper server cleanup from occurring\.
View Details
📝 Patch Details
diff --git a/packages/next/src/server/lib/cpu-profile.ts b/packages/next/src/server/lib/cpu-profile.ts
index e4ff13ba50..46ac9a317c 100644
--- a/packages/next/src/server/lib/cpu-profile.ts
+++ b/packages/next/src/server/lib/cpu-profile.ts
@@ -14,13 +14,8 @@ if (isCpuProfileEnabled) {
   session.post('Profiler.enable')
   session.post('Profiler.start')
 
-  // Save profile on signals (for dev server)
-  process.on('SIGINT', () => {
-    saveCpuProfile().then(() => process.exit(130))
-  })
-  process.on('SIGTERM', () => {
-    saveCpuProfile().then(() => process.exit(143))
-  })
+  // Note: Signal handlers for profile saving are now handled in start-server.ts
+  // to ensure proper coordination with server cleanup
 }
 
 /**
diff --git a/packages/next/src/server/lib/start-server.ts b/packages/next/src/server/lib/start-server.ts
index e7a80bb55b..729b1ad032 100644
--- a/packages/next/src/server/lib/start-server.ts
+++ b/packages/next/src/server/lib/start-server.ts
@@ -1,5 +1,6 @@
 // Start CPU profile if it wasn't already started.
 import './cpu-profile'
+import { saveCpuProfile } from './cpu-profile'
 import { getNetworkHost } from '../../lib/get-network-host'
 
 if (performance.getEntriesByName('next-start').length === 0) {
@@ -378,7 +379,7 @@ export async function startServer(
 
         let cleanupStarted = false
         let closeUpgraded: (() => void) | null = null
-        const cleanup = () => {
+        const cleanup = (signal?: NodeJS.Signals) => {
           if (cleanupStarted) {
             // We can get duplicate signals, e.g. when `ctrl+c` is used in an
             // interactive shell (i.e. bash, zsh), the shell will recursively
@@ -430,16 +431,24 @@ export async function startServer(
               }
             }
 
+            // Save CPU profile if enabled before exiting to avoid race conditions
+            // between CPU profile saving and server cleanup
+            await saveCpuProfile()
+
             debug('start-server process cleanup finished')
-            process.exit(0)
+            // Use appropriate exit code based on signal received
+            // SIGINT = 130, SIGTERM = 143, default = 0
+            const exitCode =
+              signal === 'SIGINT' ? 130 : signal === 'SIGTERM' ? 143 : 0
+            process.exit(exitCode)
           })()
         }
 
         // Make sure commands gracefully respect termination signals (e.g. from Docker)
         // Allow the graceful termination to be manually configurable
         if (!process.env.NEXT_MANUAL_SIG_HANDLE) {
-          process.on('SIGINT', cleanup)
-          process.on('SIGTERM', cleanup)
+          process.on('SIGINT', () => cleanup('SIGINT'))
+          process.on('SIGTERM', () => cleanup('SIGTERM'))
         }
 
         const initResult = await getRequestHandlers({

Analysis

Race condition between CPU profile saving and server cleanup in dev mode

What fails: When CPU profiling is enabled (next dev --cpu-profile), signal handlers in the child process (dev server) race to handle SIGINT/SIGTERM. The cpu-profile handlers call process.exit() before the cleanup handler completes server shutdown and telemetry flush, or vice versa. This results in either the CPU profile not being saved or the server not properly cleaning up.

How to reproduce:

# Start Next.js dev server with CPU profiling enabled
next dev --cpu-profile

# Press Ctrl+C to send SIGINT
# The process may exit with code 130 (from cpu-profile handler) before telemetry flushes
# Or exit with code 0 (from cleanup handler) before CPU profile saves

What happens: EventEmitter calls multiple signal handlers synchronously in registration order. Both handlers complete their synchronous code, then their async operations (promises) race:

  1. cpu-profile handler calls saveCpuProfile().then(() => process.exit(130))
  2. cleanup handler runs async cleanup then calls process.exit(0)
  3. The first promise to resolve wins and exits the process, interrupting the other

Result: Either:

  • Server closes before CPU profile saves (profile not saved to disk)
  • CPU profile handler exits before cleanup completes (connections not closed, telemetry not flushed)

Expected: Both CPU profile saving and server cleanup should complete before process exits, with proper exit code preservation.

Fix implemented:

  • Removed signal handlers from cpu-profile.ts that call process.exit()
  • Modified cleanup handler in start-server.ts to call saveCpuProfile() before exiting
  • Preserved proper exit codes (130 for SIGINT, 143 for SIGTERM)
  • This ensures both operations complete sequentially before the process exits
Fix on Vercel

@feedthejim feedthejim changed the base branch from perf-stats-improvements to graphite-base/87946 December 30, 2025 18:13
@feedthejim feedthejim force-pushed the perf-stats-improvements branch from dddf766 to ca6585f Compare January 5, 2026 08:34
@feedthejim feedthejim force-pushed the perf-stats-improvements branch from ca6585f to 9080141 Compare January 5, 2026 08:39
@feedthejim feedthejim force-pushed the perf-stats-improvements branch from 9080141 to 75312e9 Compare January 5, 2026 08:58
@nextjs-bot
Copy link
Collaborator

nextjs-bot commented Jan 5, 2026

Stats from current PR

Default Build (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
buildDuration 17.1s 15.1s N/A
buildDurationCached 14s 11s N/A
nodeModulesSize 457 MB 457 MB ⚠️ +49.7 kB
nextStartRea..uration (ms) 716ms 717ms N/A
Client Bundles (main, webpack) Overall increase ⚠️
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
2086.HASH.js gzip 169 B 169 B
2161-HASH.js gzip 5.39 kB 5.41 kB N/A
2747-HASH.js gzip 4.48 kB 4.46 kB N/A
4322-HASH.js gzip 51.2 kB 51 kB N/A
ec793fe8-HASH.js gzip 62.3 kB 62.3 kB N/A
framework-HASH.js gzip 59.8 kB 59.8 kB N/A
main-app-HASH.js gzip 251 B 253 B N/A
main-HASH.js gzip 38.4 kB 38.7 kB ⚠️ +368 B
webpack-HASH.js gzip 1.68 kB 1.69 kB N/A
Overall change 38.5 kB 38.9 kB ⚠️ +368 B
Legacy Client Bundles (polyfills)
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
polyfills-HASH.js gzip 39.4 kB 39.4 kB
Overall change 39.4 kB 39.4 kB
Client Pages
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
_app-HASH.js gzip 194 B 193 B N/A
_error-HASH.js gzip 182 B 182 B
css-HASH.js gzip 336 B 335 B N/A
dynamic-HASH.js gzip 1.8 kB 1.8 kB N/A
edge-ssr-HASH.js gzip 256 B 256 B
head-HASH.js gzip 352 B 349 B N/A
hooks-HASH.js gzip 385 B 384 B N/A
image-HASH.js gzip 580 B 580 B
index-HASH.js gzip 259 B 258 B N/A
link-HASH.js gzip 2.5 kB 2.51 kB N/A
routerDirect..HASH.js gzip 319 B 317 B N/A
script-HASH.js gzip 385 B 387 B N/A
withRouter-HASH.js gzip 316 B 315 B N/A
1afbb74e6ecf..834.css gzip 106 B 106 B
Overall change 1.12 kB 1.12 kB
Client Build Manifests
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
_buildManifest.js gzip 738 B 738 B
Overall change 738 B 738 B
Rendered Page Sizes
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
index.html gzip 523 B 525 B N/A
link.html gzip 537 B 539 B N/A
withRouter.html gzip 520 B 521 B N/A
Overall change 0 B 0 B
Edge SSR bundle Size Overall increase ⚠️
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
edge-ssr.js gzip 124 kB 124 kB N/A
page.js gzip 237 kB 238 kB ⚠️ +597 B
Overall change 237 kB 238 kB ⚠️ +597 B
Middleware size Overall increase ⚠️
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
middleware-b..fest.js gzip 653 B 658 B N/A
middleware-r..fest.js gzip 155 B 156 B N/A
middleware.js gzip 32.6 kB 32.9 kB ⚠️ +343 B
edge-runtime..pack.js gzip 846 B 846 B
Overall change 33.4 kB 33.7 kB ⚠️ +343 B
Next Runtimes
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
app-page-exp...dev.js gzip 301 kB 301 kB N/A
app-page-exp..prod.js gzip 156 kB 156 kB
app-page-tur...dev.js gzip 301 kB 301 kB N/A
app-page-tur..prod.js gzip 156 kB 156 kB
app-page-tur...dev.js gzip 298 kB 298 kB
app-page-tur..prod.js gzip 154 kB 154 kB
app-page.run...dev.js gzip 298 kB 298 kB
app-page.run..prod.js gzip 154 kB 154 kB
app-route-ex...dev.js gzip 68.7 kB 68.7 kB
app-route-ex..prod.js gzip 47.5 kB 47.5 kB
app-route-tu...dev.js gzip 68.7 kB 68.7 kB
app-route-tu..prod.js gzip 47.5 kB 47.5 kB
app-route-tu...dev.js gzip 68.3 kB 68.3 kB
app-route-tu..prod.js gzip 47.3 kB 47.3 kB
app-route.ru...dev.js gzip 68.3 kB 68.3 kB
app-route.ru..prod.js gzip 47.3 kB 47.3 kB
dist_client_...dev.js gzip 324 B 324 B
dist_client_...dev.js gzip 326 B 326 B
dist_client_...dev.js gzip 318 B 318 B
dist_client_...dev.js gzip 317 B 317 B
pages-api-tu...dev.js gzip 41.1 kB 41.1 kB
pages-api-tu..prod.js gzip 31.2 kB 31.2 kB N/A
pages-api.ru...dev.js gzip 41 kB 41 kB
pages-api.ru..prod.js gzip 31.2 kB 31.2 kB
pages-turbo....dev.js gzip 50.7 kB 50.7 kB
pages-turbo...prod.js gzip 38.2 kB 38.2 kB N/A
pages.runtim...dev.js gzip 50.6 kB 50.6 kB
pages.runtim..prod.js gzip 38.1 kB 38.1 kB
server.runti..prod.js gzip 59.9 kB 59.9 kB
Overall change 1.99 MB 1.99 MB
build cache Overall increase ⚠️
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
0.pack gzip 3.61 MB 3.61 MB ⚠️ +7.47 kB
index.pack gzip 98.9 kB 98.5 kB N/A
Overall change 3.61 MB 3.61 MB ⚠️ +7.47 kB
Diff details
Diff for page.js

Diff too large to display

Diff for middleware.js

Diff too large to display

Diff for edge-ssr.js

Diff too large to display

Diff for _buildManifest.js
@@ -611,35 +611,35 @@ self.__BUILD_MANIFEST = (function (a, b, c) {
       numHashes: NaN,
       bitArray: [],
     },
-    "/": ["static\u002Fchunks\u002Fpages\u002Findex-dda7d8b64d4ba15c.js"],
+    "/": ["static\u002Fchunks\u002Fpages\u002Findex-d95f7ec6af4d2644.js"],
     "/_error": [
-      "static\u002Fchunks\u002Fpages\u002F_error-6ef44d3954f25711.js",
+      "static\u002Fchunks\u002Fpages\u002F_error-209c0c82205a7c9f.js",
     ],
     "/css": [
       "static\u002Fcss\u002Fded6b86ab9cc0a1f.css",
-      "static\u002Fchunks\u002Fpages\u002Fcss-c8aaa7211416a045.js",
+      "static\u002Fchunks\u002Fpages\u002Fcss-62710339bc830ded.js",
     ],
     "/dynamic": [
-      "static\u002Fchunks\u002Fpages\u002Fdynamic-d53bb7f318f342c2.js",
+      "static\u002Fchunks\u002Fpages\u002Fdynamic-8ed3486bb68dd6c6.js",
     ],
     "/edge-ssr": [
-      "static\u002Fchunks\u002Fpages\u002Fedge-ssr-1383106d4a3e7d72.js",
+      "static\u002Fchunks\u002Fpages\u002Fedge-ssr-0db9f7bb610d3072.js",
     ],
-    "/head": ["static\u002Fchunks\u002Fpages\u002Fhead-1db1c4be1a45662f.js"],
-    "/hooks": ["static\u002Fchunks\u002Fpages\u002Fhooks-e6deee5b72a5b112.js"],
+    "/head": ["static\u002Fchunks\u002Fpages\u002Fhead-747416c4075e42aa.js"],
+    "/hooks": ["static\u002Fchunks\u002Fpages\u002Fhooks-8b10205be7505244.js"],
     "/image": [
-      "static\u002Fchunks\u002F2747-90c828280005c0c3.js",
-      "static\u002Fchunks\u002Fpages\u002Fimage-868472cd5e84efc9.js",
+      "static\u002Fchunks\u002F6349-ee9aecde860d4832.js",
+      "static\u002Fchunks\u002Fpages\u002Fimage-f90ae17c3ad1d38b.js",
     ],
-    "/link": ["static\u002Fchunks\u002Fpages\u002Flink-0ec374e48b2ce5d9.js"],
+    "/link": ["static\u002Fchunks\u002Fpages\u002Flink-6ab9a67b348df1bf.js"],
     "/routerDirect": [
-      "static\u002Fchunks\u002Fpages\u002FrouterDirect-1a34bfadbc088491.js",
+      "static\u002Fchunks\u002Fpages\u002FrouterDirect-f132fb471e65a8b9.js",
     ],
     "/script": [
-      "static\u002Fchunks\u002Fpages\u002Fscript-52320f59afbd096d.js",
+      "static\u002Fchunks\u002Fpages\u002Fscript-8e2028e44b8da2d9.js",
     ],
     "/withRouter": [
-      "static\u002Fchunks\u002Fpages\u002FwithRouter-3b1a16d3dfa21c16.js",
+      "static\u002Fchunks\u002Fpages\u002FwithRouter-a86d259faa012c1c.js",
     ],
     sortedPages: [
       "\u002F",
Diff for dynamic-HASH.js
@@ -1,17 +1,24 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [2291],
   {
-    /***/ 1231: /***/ (
-      module,
+    /***/ 2604: /***/ (
+      __unused_webpack_module,
       __unused_webpack_exports,
       __webpack_require__
     ) => {
-      module.exports = __webpack_require__(4464);
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/dynamic",
+        function () {
+          return __webpack_require__(3643);
+        },
+      ]);
+      if (false) {
+      }
 
       /***/
     },
 
-    /***/ 2101: /***/ (
+    /***/ 3401: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -38,24 +45,63 @@
       /***/
     },
 
-    /***/ 3458: /***/ (
+    /***/ 3643: /***/ (
       __unused_webpack_module,
-      __unused_webpack_exports,
+      __webpack_exports__,
       __webpack_require__
     ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/dynamic",
-        function () {
-          return __webpack_require__(9381);
-        },
-      ]);
-      if (false) {
-      }
+      "use strict";
+      __webpack_require__.r(__webpack_exports__);
+      /* harmony export */ __webpack_require__.d(__webpack_exports__, {
+        /* harmony export */ __N_SSP: () => /* binding */ __N_SSP,
+        /* harmony export */ default: () => __WEBPACK_DEFAULT_EXPORT__,
+        /* harmony export */
+      });
+      /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
+        __webpack_require__(3108);
+      /* harmony import */ var next_dynamic__WEBPACK_IMPORTED_MODULE_1__ =
+        __webpack_require__(3973);
+      /* harmony import */ var next_dynamic__WEBPACK_IMPORTED_MODULE_1___default =
+        /*#__PURE__*/ __webpack_require__.n(
+          next_dynamic__WEBPACK_IMPORTED_MODULE_1__
+        );
+
+      const DynamicHello = next_dynamic__WEBPACK_IMPORTED_MODULE_1___default()(
+        () =>
+          __webpack_require__
+            .e(/* import() */ 1596)
+            .then(__webpack_require__.bind(__webpack_require__, 1596))
+            .then((mod) => mod.Hello),
+        {
+          loadableGenerated: {
+            webpack: () => [/*require.resolve*/ 1596],
+          },
+        }
+      );
+      const Page = () =>
+        /*#__PURE__*/ (0, react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(
+          react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment,
+          {
+            children: [
+              /*#__PURE__*/ (0,
+              react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
+                children: "testing next/dynamic size",
+              }),
+              /*#__PURE__*/ (0,
+              react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(
+                DynamicHello,
+                {}
+              ),
+            ],
+          }
+        );
+      var __N_SSP = true;
+      /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = Page;
 
       /***/
     },
 
-    /***/ 4464: /***/ (module, exports, __webpack_require__) => {
+    /***/ 3660: /***/ (module, exports, __webpack_require__) => {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
@@ -88,7 +134,7 @@
         __webpack_require__(4312)
       );
       const _loadablesharedruntime = /*#__PURE__*/ _interop_require_default._(
-        __webpack_require__(9799)
+        __webpack_require__(4539)
       );
       const isServerSide = "object" === "undefined";
       // Normalize loader to return the module as form { default: Component } for `React.lazy`.
@@ -188,63 +234,17 @@
       /***/
     },
 
-    /***/ 9381: /***/ (
-      __unused_webpack_module,
-      __webpack_exports__,
+    /***/ 3973: /***/ (
+      module,
+      __unused_webpack_exports,
       __webpack_require__
     ) => {
-      "use strict";
-      __webpack_require__.r(__webpack_exports__);
-      /* harmony export */ __webpack_require__.d(__webpack_exports__, {
-        /* harmony export */ __N_SSP: () => /* binding */ __N_SSP,
-        /* harmony export */ default: () => __WEBPACK_DEFAULT_EXPORT__,
-        /* harmony export */
-      });
-      /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
-        __webpack_require__(3108);
-      /* harmony import */ var next_dynamic__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(1231);
-      /* harmony import */ var next_dynamic__WEBPACK_IMPORTED_MODULE_1___default =
-        /*#__PURE__*/ __webpack_require__.n(
-          next_dynamic__WEBPACK_IMPORTED_MODULE_1__
-        );
-
-      const DynamicHello = next_dynamic__WEBPACK_IMPORTED_MODULE_1___default()(
-        () =>
-          __webpack_require__
-            .e(/* import() */ 2086)
-            .then(__webpack_require__.bind(__webpack_require__, 2086))
-            .then((mod) => mod.Hello),
-        {
-          loadableGenerated: {
-            webpack: () => [/*require.resolve*/ 2086],
-          },
-        }
-      );
-      const Page = () =>
-        /*#__PURE__*/ (0, react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(
-          react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment,
-          {
-            children: [
-              /*#__PURE__*/ (0,
-              react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
-                children: "testing next/dynamic size",
-              }),
-              /*#__PURE__*/ (0,
-              react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(
-                DynamicHello,
-                {}
-              ),
-            ],
-          }
-        );
-      var __N_SSP = true;
-      /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = Page;
+      module.exports = __webpack_require__(3660);
 
       /***/
     },
 
-    /***/ 9799: /***/ (
+    /***/ 4539: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -286,7 +286,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
       const _react = /*#__PURE__*/ _interop_require_default._(
         __webpack_require__(4312)
       );
-      const _loadablecontextsharedruntime = __webpack_require__(2101);
+      const _loadablecontextsharedruntime = __webpack_require__(3401);
       function resolve(obj) {
         return obj && obj.default ? obj.default : obj;
       }
@@ -524,7 +524,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(3458)
+      __webpack_exec__(2604)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for edge-ssr-HASH.js
@@ -1,7 +1,24 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [676],
   {
-    /***/ 1564: /***/ (
+    /***/ 7046: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/edge-ssr",
+        function () {
+          return __webpack_require__(7142);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
+
+    /***/ 7142: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -20,30 +37,13 @@
 
       /***/
     },
-
-    /***/ 4300: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/edge-ssr",
-        function () {
-          return __webpack_require__(1564);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(4300)
+      __webpack_exec__(7046)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for head-HASH.js
@@ -1,34 +1,17 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [5350],
   {
-    /***/ 1548: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/head",
-        function () {
-          return __webpack_require__(4282);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
-
-    /***/ 3952: /***/ (
+    /***/ 3770: /***/ (
       module,
       __unused_webpack_exports,
       __webpack_require__
     ) => {
-      module.exports = __webpack_require__(1653);
+      module.exports = __webpack_require__(9025);
 
       /***/
     },
 
-    /***/ 4282: /***/ (
+    /***/ 6236: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -43,7 +26,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(3108);
       /* harmony import */ var next_head__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(3952);
+        __webpack_require__(3770);
       /* harmony import */ var next_head__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_head__WEBPACK_IMPORTED_MODULE_1__
@@ -76,13 +59,30 @@
 
       /***/
     },
+
+    /***/ 6510: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/head",
+        function () {
+          return __webpack_require__(6236);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(1548)
+      __webpack_exec__(6510)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for index-HASH.js
@@ -1,24 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [3332],
   {
-    /***/ 6376: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/",
-        function () {
-          return __webpack_require__(8460);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
-
-    /***/ 8460: /***/ (
+    /***/ 830: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -36,13 +19,30 @@
 
       /***/
     },
+
+    /***/ 1938: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/",
+        function () {
+          return __webpack_require__(830);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(6376)
+      __webpack_exec__(1938)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for link-HASH.js
@@ -1,7 +1,220 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [4672],
   {
-    /***/ 857: /***/ (module, exports, __webpack_require__) => {
+    /***/ 2774: /***/ (module, exports, __webpack_require__) => {
+      "use strict";
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true,
+      });
+      Object.defineProperty(exports, "useIntersection", {
+        enumerable: true,
+        get: function () {
+          return useIntersection;
+        },
+      });
+      const _react = __webpack_require__(4312);
+      const _requestidlecallback = __webpack_require__(9413);
+      const hasIntersectionObserver =
+        typeof IntersectionObserver === "function";
+      const observers = new Map();
+      const idList = [];
+      function createObserver(options) {
+        const id = {
+          root: options.root || null,
+          margin: options.rootMargin || "",
+        };
+        const existing = idList.find(
+          (obj) => obj.root === id.root && obj.margin === id.margin
+        );
+        let instance;
+        if (existing) {
+          instance = observers.get(existing);
+          if (instance) {
+            return instance;
+          }
+        }
+        const elements = new Map();
+        const observer = new IntersectionObserver((entries) => {
+          entries.forEach((entry) => {
+            const callback = elements.get(entry.target);
+            const isVisible =
+              entry.isIntersecting || entry.intersectionRatio > 0;
+            if (callback && isVisible) {
+              callback(isVisible);
+            }
+          });
+        }, options);
+        instance = {
+          id,
+          observer,
+          elements,
+        };
+        idList.push(id);
+        observers.set(id, instance);
+        return instance;
+      }
+      function observe(element, callback, options) {
+        const { id, observer, elements } = createObserver(options);
+        elements.set(element, callback);
+        observer.observe(element);
+        return function unobserve() {
+          elements.delete(element);
+          observer.unobserve(element);
+          // Destroy observer when there's nothing left to watch:
+          if (elements.size === 0) {
+            observer.disconnect();
+            observers.delete(id);
+            const index = idList.findIndex(
+              (obj) => obj.root === id.root && obj.margin === id.margin
+            );
+            if (index > -1) {
+              idList.splice(index, 1);
+            }
+          }
+        };
+      }
+      function useIntersection({ rootRef, rootMargin, disabled }) {
+        const isDisabled = disabled || !hasIntersectionObserver;
+        const [visible, setVisible] = (0, _react.useState)(false);
+        const elementRef = (0, _react.useRef)(null);
+        const setElement = (0, _react.useCallback)((element) => {
+          elementRef.current = element;
+        }, []);
+        (0, _react.useEffect)(() => {
+          if (hasIntersectionObserver) {
+            if (isDisabled || visible) return;
+            const element = elementRef.current;
+            if (element && element.tagName) {
+              const unobserve = observe(
+                element,
+                (isVisible) => isVisible && setVisible(isVisible),
+                {
+                  root: rootRef?.current,
+                  rootMargin,
+                }
+              );
+              return unobserve;
+            }
+          } else {
+            if (!visible) {
+              const idleCallback = (0,
+              _requestidlecallback.requestIdleCallback)(() => setVisible(true));
+              return () =>
+                (0, _requestidlecallback.cancelIdleCallback)(idleCallback);
+            }
+          }
+          // eslint-disable-next-line react-hooks/exhaustive-deps
+        }, [isDisabled, rootMargin, rootRef, visible, elementRef.current]);
+        const resetVisible = (0, _react.useCallback)(() => {
+          setVisible(false);
+        }, []);
+        return [setElement, visible, resetVisible];
+      }
+      if (
+        (typeof exports.default === "function" ||
+          (typeof exports.default === "object" && exports.default !== null)) &&
+        typeof exports.default.__esModule === "undefined"
+      ) {
+        Object.defineProperty(exports.default, "__esModule", {
+          value: true,
+        });
+        Object.assign(exports.default, exports);
+        module.exports = exports.default;
+      } //# sourceMappingURL=use-intersection.js.map
+
+      /***/
+    },
+
+    /***/ 3351: /***/ (module, exports, __webpack_require__) => {
+      "use strict";
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true,
+      });
+      Object.defineProperty(exports, "useMergedRef", {
+        enumerable: true,
+        get: function () {
+          return useMergedRef;
+        },
+      });
+      const _react = __webpack_require__(4312);
+      function useMergedRef(refA, refB) {
+        const cleanupA = (0, _react.useRef)(null);
+        const cleanupB = (0, _react.useRef)(null);
+        // NOTE: In theory, we could skip the wrapping if only one of the refs is non-null.
+        // (this happens often if the user doesn't pass a ref to Link/Form/Image)
+        // But this can cause us to leak a cleanup-ref into user code (previously via `<Link legacyBehavior>`),
+        // and the user might pass that ref into ref-merging library that doesn't support cleanup refs
+        // (because it hasn't been updated for React 19)
+        // which can then cause things to blow up, because a cleanup-returning ref gets called with `null`.
+        // So in practice, it's safer to be defensive and always wrap the ref, even on React 19.
+        return (0, _react.useCallback)(
+          (current) => {
+            if (current === null) {
+              const cleanupFnA = cleanupA.current;
+              if (cleanupFnA) {
+                cleanupA.current = null;
+                cleanupFnA();
+              }
+              const cleanupFnB = cleanupB.current;
+              if (cleanupFnB) {
+                cleanupB.current = null;
+                cleanupFnB();
+              }
+            } else {
+              if (refA) {
+                cleanupA.current = applyRef(refA, current);
+              }
+              if (refB) {
+                cleanupB.current = applyRef(refB, current);
+              }
+            }
+          },
+          [refA, refB]
+        );
+      }
+      function applyRef(refA, current) {
+        if (typeof refA === "function") {
+          const cleanup = refA(current);
+          if (typeof cleanup === "function") {
+            return cleanup;
+          } else {
+            return () => refA(null);
+          }
+        } else {
+          refA.current = current;
+          return () => {
+            refA.current = null;
+          };
+        }
+      }
+      if (
+        (typeof exports.default === "function" ||
+          (typeof exports.default === "object" && exports.default !== null)) &&
+        typeof exports.default.__esModule === "undefined"
+      ) {
+        Object.defineProperty(exports.default, "__esModule", {
+          value: true,
+        });
+        Object.assign(exports.default, exports);
+        module.exports = exports.default;
+      } //# sourceMappingURL=use-merged-ref.js.map
+
+      /***/
+    },
+
+    /***/ 3440: /***/ (
+      module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      module.exports = __webpack_require__(4757);
+
+      /***/
+    },
+
+    /***/ 4757: /***/ (module, exports, __webpack_require__) => {
       "use strict";
       /* __next_internal_client_entry_do_not_use__  cjs */
       Object.defineProperty(exports, "__esModule", {
@@ -23,22 +236,22 @@
           return useLinkStatus;
         },
       });
-      const _interop_require_wildcard = __webpack_require__(8781);
+      const _interop_require_wildcard = __webpack_require__(1162);
       const _jsxruntime = __webpack_require__(3108);
       const _react = /*#__PURE__*/ _interop_require_wildcard._(
         __webpack_require__(4312)
       );
-      const _resolvehref = __webpack_require__(4055);
-      const _islocalurl = __webpack_require__(7175);
-      const _formaturl = __webpack_require__(9674);
-      const _utils = __webpack_require__(7424);
-      const _addlocale = __webpack_require__(589);
-      const _routercontextsharedruntime = __webpack_require__(7010);
-      const _useintersection = __webpack_require__(2330);
-      const _getdomainlocale = __webpack_require__(7207);
-      const _addbasepath = __webpack_require__(9942);
-      const _usemergedref = __webpack_require__(8067);
-      const _erroronce = __webpack_require__(1945);
+      const _resolvehref = __webpack_require__(4691);
+      const _islocalurl = __webpack_require__(4763);
+      const _formaturl = __webpack_require__(3246);
+      const _utils = __webpack_require__(7372);
+      const _addlocale = __webpack_require__(1809);
+      const _routercontextsharedruntime = __webpack_require__(2254);
+      const _useintersection = __webpack_require__(2774);
+      const _getdomainlocale = __webpack_require__(8803);
+      const _addbasepath = __webpack_require__(5834);
+      const _usemergedref = __webpack_require__(3351);
+      const _erroronce = __webpack_require__(6021);
       const prefetched = new Set();
       function prefetch(router, href, as, options) {
         if (false) {
@@ -417,168 +630,43 @@
       /***/
     },
 
-    /***/ 1945: /***/ (__unused_webpack_module, exports) => {
-      "use strict";
-
-      Object.defineProperty(exports, "__esModule", {
-        value: true,
-      });
-      Object.defineProperty(exports, "errorOnce", {
-        enumerable: true,
-        get: function () {
-          return errorOnce;
+    /***/ 5326: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/link",
+        function () {
+          return __webpack_require__(9058);
         },
-      });
-      let errorOnce = (_) => {};
+      ]);
       if (false) {
-      } //# sourceMappingURL=error-once.js.map
+      }
 
       /***/
     },
 
-    /***/ 2330: /***/ (module, exports, __webpack_require__) => {
+    /***/ 6021: /***/ (__unused_webpack_module, exports) => {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
         value: true,
       });
-      Object.defineProperty(exports, "useIntersection", {
+      Object.defineProperty(exports, "errorOnce", {
         enumerable: true,
         get: function () {
-          return useIntersection;
+          return errorOnce;
         },
       });
-      const _react = __webpack_require__(4312);
-      const _requestidlecallback = __webpack_require__(601);
-      const hasIntersectionObserver =
-        typeof IntersectionObserver === "function";
-      const observers = new Map();
-      const idList = [];
-      function createObserver(options) {
-        const id = {
-          root: options.root || null,
-          margin: options.rootMargin || "",
-        };
-        const existing = idList.find(
-          (obj) => obj.root === id.root && obj.margin === id.margin
-        );
-        let instance;
-        if (existing) {
-          instance = observers.get(existing);
-          if (instance) {
-            return instance;
-          }
-        }
-        const elements = new Map();
-        const observer = new IntersectionObserver((entries) => {
-          entries.forEach((entry) => {
-            const callback = elements.get(entry.target);
-            const isVisible =
-              entry.isIntersecting || entry.intersectionRatio > 0;
-            if (callback && isVisible) {
-              callback(isVisible);
-            }
-          });
-        }, options);
-        instance = {
-          id,
-          observer,
-          elements,
-        };
-        idList.push(id);
-        observers.set(id, instance);
-        return instance;
-      }
-      function observe(element, callback, options) {
-        const { id, observer, elements } = createObserver(options);
-        elements.set(element, callback);
-        observer.observe(element);
-        return function unobserve() {
-          elements.delete(element);
-          observer.unobserve(element);
-          // Destroy observer when there's nothing left to watch:
-          if (elements.size === 0) {
-            observer.disconnect();
-            observers.delete(id);
-            const index = idList.findIndex(
-              (obj) => obj.root === id.root && obj.margin === id.margin
-            );
-            if (index > -1) {
-              idList.splice(index, 1);
-            }
-          }
-        };
-      }
-      function useIntersection({ rootRef, rootMargin, disabled }) {
-        const isDisabled = disabled || !hasIntersectionObserver;
-        const [visible, setVisible] = (0, _react.useState)(false);
-        const elementRef = (0, _react.useRef)(null);
-        const setElement = (0, _react.useCallback)((element) => {
-          elementRef.current = element;
-        }, []);
-        (0, _react.useEffect)(() => {
-          if (hasIntersectionObserver) {
-            if (isDisabled || visible) return;
-            const element = elementRef.current;
-            if (element && element.tagName) {
-              const unobserve = observe(
-                element,
-                (isVisible) => isVisible && setVisible(isVisible),
-                {
-                  root: rootRef?.current,
-                  rootMargin,
-                }
-              );
-              return unobserve;
-            }
-          } else {
-            if (!visible) {
-              const idleCallback = (0,
-              _requestidlecallback.requestIdleCallback)(() => setVisible(true));
-              return () =>
-                (0, _requestidlecallback.cancelIdleCallback)(idleCallback);
-            }
-          }
-          // eslint-disable-next-line react-hooks/exhaustive-deps
-        }, [isDisabled, rootMargin, rootRef, visible, elementRef.current]);
-        const resetVisible = (0, _react.useCallback)(() => {
-          setVisible(false);
-        }, []);
-        return [setElement, visible, resetVisible];
-      }
-      if (
-        (typeof exports.default === "function" ||
-          (typeof exports.default === "object" && exports.default !== null)) &&
-        typeof exports.default.__esModule === "undefined"
-      ) {
-        Object.defineProperty(exports.default, "__esModule", {
-          value: true,
-        });
-        Object.assign(exports.default, exports);
-        module.exports = exports.default;
-      } //# sourceMappingURL=use-intersection.js.map
-
-      /***/
-    },
-
-    /***/ 4972: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/link",
-        function () {
-          return __webpack_require__(7600);
-        },
-      ]);
+      let errorOnce = (_) => {};
       if (false) {
-      }
+      } //# sourceMappingURL=error-once.js.map
 
       /***/
     },
 
-    /***/ 7207: /***/ (module, exports, __webpack_require__) => {
+    /***/ 8803: /***/ (module, exports, __webpack_require__) => {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
@@ -590,7 +678,7 @@
           return getDomainLocale;
         },
       });
-      const _normalizetrailingslash = __webpack_require__(151);
+      const _normalizetrailingslash = __webpack_require__(1315);
       const basePath =
         /* unused pure expression or super */ null && (false || "");
       function getDomainLocale(path, locale, locales, domainLocales) {
@@ -614,7 +702,7 @@
       /***/
     },
 
-    /***/ 7600: /***/ (
+    /***/ 9058: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -629,7 +717,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(3108);
       /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(7830);
+        __webpack_require__(3440);
       /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_link__WEBPACK_IMPORTED_MODULE_1__
@@ -659,101 +747,13 @@
 
       /***/
     },
-
-    /***/ 7830: /***/ (
-      module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      module.exports = __webpack_require__(857);
-
-      /***/
-    },
-
-    /***/ 8067: /***/ (module, exports, __webpack_require__) => {
-      "use strict";
-
-      Object.defineProperty(exports, "__esModule", {
-        value: true,
-      });
-      Object.defineProperty(exports, "useMergedRef", {
-        enumerable: true,
-        get: function () {
-          return useMergedRef;
-        },
-      });
-      const _react = __webpack_require__(4312);
-      function useMergedRef(refA, refB) {
-        const cleanupA = (0, _react.useRef)(null);
-        const cleanupB = (0, _react.useRef)(null);
-        // NOTE: In theory, we could skip the wrapping if only one of the refs is non-null.
-        // (this happens often if the user doesn't pass a ref to Link/Form/Image)
-        // But this can cause us to leak a cleanup-ref into user code (previously via `<Link legacyBehavior>`),
-        // and the user might pass that ref into ref-merging library that doesn't support cleanup refs
-        // (because it hasn't been updated for React 19)
-        // which can then cause things to blow up, because a cleanup-returning ref gets called with `null`.
-        // So in practice, it's safer to be defensive and always wrap the ref, even on React 19.
-        return (0, _react.useCallback)(
-          (current) => {
-            if (current === null) {
-              const cleanupFnA = cleanupA.current;
-              if (cleanupFnA) {
-                cleanupA.current = null;
-                cleanupFnA();
-              }
-              const cleanupFnB = cleanupB.current;
-              if (cleanupFnB) {
-                cleanupB.current = null;
-                cleanupFnB();
-              }
-            } else {
-              if (refA) {
-                cleanupA.current = applyRef(refA, current);
-              }
-              if (refB) {
-                cleanupB.current = applyRef(refB, current);
-              }
-            }
-          },
-          [refA, refB]
-        );
-      }
-      function applyRef(refA, current) {
-        if (typeof refA === "function") {
-          const cleanup = refA(current);
-          if (typeof cleanup === "function") {
-            return cleanup;
-          } else {
-            return () => refA(null);
-          }
-        } else {
-          refA.current = current;
-          return () => {
-            refA.current = null;
-          };
-        }
-      }
-      if (
-        (typeof exports.default === "function" ||
-          (typeof exports.default === "object" && exports.default !== null)) &&
-        typeof exports.default.__esModule === "undefined"
-      ) {
-        Object.defineProperty(exports.default, "__esModule", {
-          value: true,
-        });
-        Object.assign(exports.default, exports);
-        module.exports = exports.default;
-      } //# sourceMappingURL=use-merged-ref.js.map
-
-      /***/
-    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(4972)
+      __webpack_exec__(5326)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for routerDirect-HASH.js
@@ -1,17 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [188],
   {
-    /***/ 1179: /***/ (
-      module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      module.exports = __webpack_require__(9864);
-
-      /***/
-    },
-
-    /***/ 1640: /***/ (
+    /***/ 2014: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -26,7 +16,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(3108);
       /* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(1179);
+        __webpack_require__(4169);
       /* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_router__WEBPACK_IMPORTED_MODULE_1__
@@ -46,7 +36,17 @@
       /***/
     },
 
-    /***/ 2172: /***/ (
+    /***/ 4169: /***/ (
+      module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      module.exports = __webpack_require__(9700);
+
+      /***/
+    },
+
+    /***/ 4414: /***/ (
       __unused_webpack_module,
       __unused_webpack_exports,
       __webpack_require__
@@ -54,7 +54,7 @@
       (window.__NEXT_P = window.__NEXT_P || []).push([
         "/routerDirect",
         function () {
-          return __webpack_require__(1640);
+          return __webpack_require__(2014);
         },
       ]);
       if (false) {
@@ -68,7 +68,7 @@
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(2172)
+      __webpack_exec__(4414)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for script-HASH.js
@@ -1,17 +1,34 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [1209],
   {
-    /***/ 4977: /***/ (
+    /***/ 2591: /***/ (
       module,
       __unused_webpack_exports,
       __webpack_require__
     ) => {
-      module.exports = __webpack_require__(326);
+      module.exports = __webpack_require__(4634);
 
       /***/
     },
 
-    /***/ 5887: /***/ (
+    /***/ 5030: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/script",
+        function () {
+          return __webpack_require__(7557);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
+
+    /***/ 7557: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -26,7 +43,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(3108);
       /* harmony import */ var next_script__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(4977);
+        __webpack_require__(2591);
       /* harmony import */ var next_script__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_script__WEBPACK_IMPORTED_MODULE_1__
@@ -58,30 +75,13 @@
 
       /***/
     },
-
-    /***/ 6268: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/script",
-        function () {
-          return __webpack_require__(5887);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(6268)
+      __webpack_exec__(5030)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for withRouter-HASH.js
@@ -1,34 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [3263],
   {
-    /***/ 1179: /***/ (
-      module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      module.exports = __webpack_require__(9864);
-
-      /***/
-    },
-
-    /***/ 2028: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/withRouter",
-        function () {
-          return __webpack_require__(4501);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
-
-    /***/ 4501: /***/ (
+    /***/ 559: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -43,7 +16,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(3108);
       /* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(1179);
+        __webpack_require__(4169);
       /* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_router__WEBPACK_IMPORTED_MODULE_1__
@@ -61,13 +34,40 @@
 
       /***/
     },
+
+    /***/ 726: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/withRouter",
+        function () {
+          return __webpack_require__(559);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
+
+    /***/ 4169: /***/ (
+      module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      module.exports = __webpack_require__(9700);
+
+      /***/
+    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(2028)
+      __webpack_exec__(726)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for 2161-HASH.js

Diff too large to display

Diff for 2747-HASH.js

Diff too large to display

Diff for 4322-HASH.js
failed to diff
Diff for main-HASH.js

Diff too large to display

Diff for main-app-HASH.js
@@ -1,64 +1,64 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [4977],
   {
-    /***/ 341: /***/ () => {
-      /* (ignored) */
-      /***/
-    },
-
-    /***/ 3274: /***/ (
+    /***/ 2734: /***/ (
       __unused_webpack_module,
       __unused_webpack_exports,
       __webpack_require__
     ) => {
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 375, 23)
+        __webpack_require__.t.bind(__webpack_require__, 7413, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 2972, 23)
+        __webpack_require__.t.bind(__webpack_require__, 9898, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 7508, 23)
+        __webpack_require__.t.bind(__webpack_require__, 9854, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 6043, 23)
+        __webpack_require__.t.bind(__webpack_require__, 9261, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 9797, 23)
+        __webpack_require__.t.bind(__webpack_require__, 867, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 2933, 23)
+        __webpack_require__.t.bind(__webpack_require__, 2463, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 4220, 23)
+        __webpack_require__.t.bind(__webpack_require__, 1866, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 97, 23)
+        __webpack_require__.t.bind(__webpack_require__, 9667, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 464, 23)
+        __webpack_require__.t.bind(__webpack_require__, 8822, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 619, 23)
+        __webpack_require__.t.bind(__webpack_require__, 1717, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 1464, 23)
+        __webpack_require__.t.bind(__webpack_require__, 5366, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.bind(__webpack_require__, 5297)
+        __webpack_require__.bind(__webpack_require__, 1155)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 7937, 23)
+        __webpack_require__.t.bind(__webpack_require__, 391, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 7584, 23)
+        __webpack_require__.t.bind(__webpack_require__, 7346, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 6826, 23)
+        __webpack_require__.t.bind(__webpack_require__, 1340, 23)
       );
 
       /***/
     },
+
+    /***/ 2751: /***/ () => {
+      /* (ignored) */
+      /***/
+    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
@@ -66,8 +66,8 @@
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(
       0,
-      [5639, 4322],
-      () => (__webpack_exec__(2193), __webpack_exec__(3274))
+      [8580, 2658],
+      () => (__webpack_exec__(9851), __webpack_exec__(2734))
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for pages-api-tu..time.prod.js

Diff too large to display

Diff for pages-turbo...time.prod.js

Diff too large to display

Commit: bffa9bc

@feedthejim feedthejim changed the base branch from perf-stats-improvements to graphite-base/87946 January 5, 2026 09:30
@feedthejim feedthejim force-pushed the graphite-base/87946 branch from 75312e9 to 40a4c11 Compare January 5, 2026 09:31
@feedthejim feedthejim changed the base branch from graphite-base/87946 to canary January 5, 2026 09:31
@nextjs-bot
Copy link
Collaborator

nextjs-bot commented Jan 5, 2026

Stats from current PR

Default Build (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
buildDuration 17.2s 14.8s N/A
buildDurationCached 13.8s 10.8s N/A
nodeModulesSize 457 MB 457 MB ⚠️ +49.5 kB
nextStartRea..uration (ms) 717ms 717ms
Client Bundles (main, webpack) Overall increase ⚠️
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
2086.HASH.js gzip 169 B 169 B
2161-HASH.js gzip 5.39 kB 5.41 kB N/A
2747-HASH.js gzip 4.48 kB 4.46 kB N/A
4322-HASH.js gzip 52.5 kB 52.2 kB N/A
ec793fe8-HASH.js gzip 62.3 kB 62.3 kB N/A
framework-HASH.js gzip 59.8 kB 59.8 kB N/A
main-app-HASH.js gzip 251 B 254 B N/A
main-HASH.js gzip 38.4 kB 38.7 kB ⚠️ +368 B
webpack-HASH.js gzip 1.68 kB 1.69 kB N/A
Overall change 38.5 kB 38.9 kB ⚠️ +368 B
Legacy Client Bundles (polyfills)
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
polyfills-HASH.js gzip 39.4 kB 39.4 kB
Overall change 39.4 kB 39.4 kB
Client Pages
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
_app-HASH.js gzip 194 B 193 B N/A
_error-HASH.js gzip 182 B 182 B
css-HASH.js gzip 336 B 335 B N/A
dynamic-HASH.js gzip 1.8 kB 1.8 kB N/A
edge-ssr-HASH.js gzip 256 B 256 B
head-HASH.js gzip 352 B 349 B N/A
hooks-HASH.js gzip 385 B 384 B N/A
image-HASH.js gzip 580 B 580 B
index-HASH.js gzip 259 B 258 B N/A
link-HASH.js gzip 2.5 kB 2.51 kB N/A
routerDirect..HASH.js gzip 319 B 317 B N/A
script-HASH.js gzip 385 B 387 B N/A
withRouter-HASH.js gzip 316 B 315 B N/A
1afbb74e6ecf..834.css gzip 106 B 106 B
Overall change 1.12 kB 1.12 kB
Client Build Manifests
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
_buildManifest.js gzip 738 B 738 B
Overall change 738 B 738 B
Rendered Page Sizes
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
index.html gzip 523 B 525 B N/A
link.html gzip 537 B 539 B N/A
withRouter.html gzip 520 B 521 B N/A
Overall change 0 B 0 B
Edge SSR bundle Size Overall increase ⚠️
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
edge-ssr.js gzip 124 kB 124 kB N/A
page.js gzip 238 kB 239 kB ⚠️ +643 B
Overall change 238 kB 239 kB ⚠️ +643 B
Middleware size Overall increase ⚠️
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
middleware-b..fest.js gzip 650 B 656 B N/A
middleware-r..fest.js gzip 155 B 156 B N/A
middleware.js gzip 32.6 kB 32.9 kB ⚠️ +263 B
edge-runtime..pack.js gzip 846 B 846 B
Overall change 33.5 kB 33.7 kB ⚠️ +263 B
Next Runtimes
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
app-page-exp...dev.js gzip 302 kB 302 kB N/A
app-page-exp..prod.js gzip 157 kB 157 kB
app-page-tur...dev.js gzip 302 kB 302 kB N/A
app-page-tur..prod.js gzip 157 kB 157 kB
app-page-tur...dev.js gzip 299 kB 299 kB N/A
app-page-tur..prod.js gzip 155 kB 155 kB
app-page.run...dev.js gzip 299 kB 299 kB N/A
app-page.run..prod.js gzip 155 kB 155 kB
app-route-ex...dev.js gzip 68.7 kB 68.7 kB
app-route-ex..prod.js gzip 47.5 kB 47.5 kB
app-route-tu...dev.js gzip 68.7 kB 68.7 kB
app-route-tu..prod.js gzip 47.5 kB 47.5 kB
app-route-tu...dev.js gzip 68.3 kB 68.3 kB
app-route-tu..prod.js gzip 47.3 kB 47.3 kB
app-route.ru...dev.js gzip 68.3 kB 68.3 kB
app-route.ru..prod.js gzip 47.3 kB 47.3 kB
dist_client_...dev.js gzip 324 B 324 B
dist_client_...dev.js gzip 326 B 326 B
dist_client_...dev.js gzip 318 B 318 B
dist_client_...dev.js gzip 317 B 317 B
pages-api-tu...dev.js gzip 41.1 kB 41.1 kB
pages-api-tu..prod.js gzip 31.2 kB 31.2 kB
pages-api.ru...dev.js gzip 41 kB 41 kB
pages-api.ru..prod.js gzip 31.2 kB 31.2 kB
pages-turbo....dev.js gzip 50.7 kB 50.7 kB
pages-turbo...prod.js gzip 38.2 kB 38.2 kB
pages.runtim...dev.js gzip 50.6 kB 50.6 kB
pages.runtim..prod.js gzip 38.1 kB 38.1 kB
server.runti..prod.js gzip 59.9 kB 59.9 kB
Overall change 1.47 MB 1.47 MB
build cache Overall increase ⚠️
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
0.pack gzip 3.62 MB 3.62 MB ⚠️ +755 B
index.pack gzip 97.8 kB 99.9 kB ⚠️ +2.18 kB
Overall change 3.72 MB 3.72 MB ⚠️ +2.94 kB
Diff details
Diff for page.js

Diff too large to display

Diff for middleware.js

Diff too large to display

Diff for edge-ssr.js

Diff too large to display

Diff for _buildManifest.js
@@ -611,35 +611,35 @@ self.__BUILD_MANIFEST = (function (a, b, c) {
       numHashes: NaN,
       bitArray: [],
     },
-    "/": ["static\u002Fchunks\u002Fpages\u002Findex-dda7d8b64d4ba15c.js"],
+    "/": ["static\u002Fchunks\u002Fpages\u002Findex-d95f7ec6af4d2644.js"],
     "/_error": [
-      "static\u002Fchunks\u002Fpages\u002F_error-6ef44d3954f25711.js",
+      "static\u002Fchunks\u002Fpages\u002F_error-209c0c82205a7c9f.js",
     ],
     "/css": [
       "static\u002Fcss\u002Fded6b86ab9cc0a1f.css",
-      "static\u002Fchunks\u002Fpages\u002Fcss-c8aaa7211416a045.js",
+      "static\u002Fchunks\u002Fpages\u002Fcss-62710339bc830ded.js",
     ],
     "/dynamic": [
-      "static\u002Fchunks\u002Fpages\u002Fdynamic-d53bb7f318f342c2.js",
+      "static\u002Fchunks\u002Fpages\u002Fdynamic-8ed3486bb68dd6c6.js",
     ],
     "/edge-ssr": [
-      "static\u002Fchunks\u002Fpages\u002Fedge-ssr-1383106d4a3e7d72.js",
+      "static\u002Fchunks\u002Fpages\u002Fedge-ssr-0db9f7bb610d3072.js",
     ],
-    "/head": ["static\u002Fchunks\u002Fpages\u002Fhead-1db1c4be1a45662f.js"],
-    "/hooks": ["static\u002Fchunks\u002Fpages\u002Fhooks-e6deee5b72a5b112.js"],
+    "/head": ["static\u002Fchunks\u002Fpages\u002Fhead-747416c4075e42aa.js"],
+    "/hooks": ["static\u002Fchunks\u002Fpages\u002Fhooks-8b10205be7505244.js"],
     "/image": [
-      "static\u002Fchunks\u002F2747-90c828280005c0c3.js",
-      "static\u002Fchunks\u002Fpages\u002Fimage-868472cd5e84efc9.js",
+      "static\u002Fchunks\u002F6349-ee9aecde860d4832.js",
+      "static\u002Fchunks\u002Fpages\u002Fimage-f90ae17c3ad1d38b.js",
     ],
-    "/link": ["static\u002Fchunks\u002Fpages\u002Flink-0ec374e48b2ce5d9.js"],
+    "/link": ["static\u002Fchunks\u002Fpages\u002Flink-6ab9a67b348df1bf.js"],
     "/routerDirect": [
-      "static\u002Fchunks\u002Fpages\u002FrouterDirect-1a34bfadbc088491.js",
+      "static\u002Fchunks\u002Fpages\u002FrouterDirect-f132fb471e65a8b9.js",
     ],
     "/script": [
-      "static\u002Fchunks\u002Fpages\u002Fscript-52320f59afbd096d.js",
+      "static\u002Fchunks\u002Fpages\u002Fscript-8e2028e44b8da2d9.js",
     ],
     "/withRouter": [
-      "static\u002Fchunks\u002Fpages\u002FwithRouter-3b1a16d3dfa21c16.js",
+      "static\u002Fchunks\u002Fpages\u002FwithRouter-a86d259faa012c1c.js",
     ],
     sortedPages: [
       "\u002F",
Diff for dynamic-HASH.js
@@ -1,17 +1,24 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [2291],
   {
-    /***/ 1231: /***/ (
-      module,
+    /***/ 2604: /***/ (
+      __unused_webpack_module,
       __unused_webpack_exports,
       __webpack_require__
     ) => {
-      module.exports = __webpack_require__(4464);
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/dynamic",
+        function () {
+          return __webpack_require__(3643);
+        },
+      ]);
+      if (false) {
+      }
 
       /***/
     },
 
-    /***/ 2101: /***/ (
+    /***/ 3401: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -38,24 +45,63 @@
       /***/
     },
 
-    /***/ 3458: /***/ (
+    /***/ 3643: /***/ (
       __unused_webpack_module,
-      __unused_webpack_exports,
+      __webpack_exports__,
       __webpack_require__
     ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/dynamic",
-        function () {
-          return __webpack_require__(9381);
-        },
-      ]);
-      if (false) {
-      }
+      "use strict";
+      __webpack_require__.r(__webpack_exports__);
+      /* harmony export */ __webpack_require__.d(__webpack_exports__, {
+        /* harmony export */ __N_SSP: () => /* binding */ __N_SSP,
+        /* harmony export */ default: () => __WEBPACK_DEFAULT_EXPORT__,
+        /* harmony export */
+      });
+      /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
+        __webpack_require__(3108);
+      /* harmony import */ var next_dynamic__WEBPACK_IMPORTED_MODULE_1__ =
+        __webpack_require__(3973);
+      /* harmony import */ var next_dynamic__WEBPACK_IMPORTED_MODULE_1___default =
+        /*#__PURE__*/ __webpack_require__.n(
+          next_dynamic__WEBPACK_IMPORTED_MODULE_1__
+        );
+
+      const DynamicHello = next_dynamic__WEBPACK_IMPORTED_MODULE_1___default()(
+        () =>
+          __webpack_require__
+            .e(/* import() */ 1596)
+            .then(__webpack_require__.bind(__webpack_require__, 1596))
+            .then((mod) => mod.Hello),
+        {
+          loadableGenerated: {
+            webpack: () => [/*require.resolve*/ 1596],
+          },
+        }
+      );
+      const Page = () =>
+        /*#__PURE__*/ (0, react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(
+          react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment,
+          {
+            children: [
+              /*#__PURE__*/ (0,
+              react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
+                children: "testing next/dynamic size",
+              }),
+              /*#__PURE__*/ (0,
+              react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(
+                DynamicHello,
+                {}
+              ),
+            ],
+          }
+        );
+      var __N_SSP = true;
+      /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = Page;
 
       /***/
     },
 
-    /***/ 4464: /***/ (module, exports, __webpack_require__) => {
+    /***/ 3660: /***/ (module, exports, __webpack_require__) => {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
@@ -88,7 +134,7 @@
         __webpack_require__(4312)
       );
       const _loadablesharedruntime = /*#__PURE__*/ _interop_require_default._(
-        __webpack_require__(9799)
+        __webpack_require__(4539)
       );
       const isServerSide = "object" === "undefined";
       // Normalize loader to return the module as form { default: Component } for `React.lazy`.
@@ -188,63 +234,17 @@
       /***/
     },
 
-    /***/ 9381: /***/ (
-      __unused_webpack_module,
-      __webpack_exports__,
+    /***/ 3973: /***/ (
+      module,
+      __unused_webpack_exports,
       __webpack_require__
     ) => {
-      "use strict";
-      __webpack_require__.r(__webpack_exports__);
-      /* harmony export */ __webpack_require__.d(__webpack_exports__, {
-        /* harmony export */ __N_SSP: () => /* binding */ __N_SSP,
-        /* harmony export */ default: () => __WEBPACK_DEFAULT_EXPORT__,
-        /* harmony export */
-      });
-      /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
-        __webpack_require__(3108);
-      /* harmony import */ var next_dynamic__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(1231);
-      /* harmony import */ var next_dynamic__WEBPACK_IMPORTED_MODULE_1___default =
-        /*#__PURE__*/ __webpack_require__.n(
-          next_dynamic__WEBPACK_IMPORTED_MODULE_1__
-        );
-
-      const DynamicHello = next_dynamic__WEBPACK_IMPORTED_MODULE_1___default()(
-        () =>
-          __webpack_require__
-            .e(/* import() */ 2086)
-            .then(__webpack_require__.bind(__webpack_require__, 2086))
-            .then((mod) => mod.Hello),
-        {
-          loadableGenerated: {
-            webpack: () => [/*require.resolve*/ 2086],
-          },
-        }
-      );
-      const Page = () =>
-        /*#__PURE__*/ (0, react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(
-          react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment,
-          {
-            children: [
-              /*#__PURE__*/ (0,
-              react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
-                children: "testing next/dynamic size",
-              }),
-              /*#__PURE__*/ (0,
-              react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(
-                DynamicHello,
-                {}
-              ),
-            ],
-          }
-        );
-      var __N_SSP = true;
-      /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = Page;
+      module.exports = __webpack_require__(3660);
 
       /***/
     },
 
-    /***/ 9799: /***/ (
+    /***/ 4539: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -286,7 +286,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
       const _react = /*#__PURE__*/ _interop_require_default._(
         __webpack_require__(4312)
       );
-      const _loadablecontextsharedruntime = __webpack_require__(2101);
+      const _loadablecontextsharedruntime = __webpack_require__(3401);
       function resolve(obj) {
         return obj && obj.default ? obj.default : obj;
       }
@@ -524,7 +524,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(3458)
+      __webpack_exec__(2604)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for edge-ssr-HASH.js
@@ -1,7 +1,24 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [676],
   {
-    /***/ 1564: /***/ (
+    /***/ 7046: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/edge-ssr",
+        function () {
+          return __webpack_require__(7142);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
+
+    /***/ 7142: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -20,30 +37,13 @@
 
       /***/
     },
-
-    /***/ 4300: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/edge-ssr",
-        function () {
-          return __webpack_require__(1564);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(4300)
+      __webpack_exec__(7046)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for head-HASH.js
@@ -1,34 +1,17 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [5350],
   {
-    /***/ 1548: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/head",
-        function () {
-          return __webpack_require__(4282);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
-
-    /***/ 3952: /***/ (
+    /***/ 3770: /***/ (
       module,
       __unused_webpack_exports,
       __webpack_require__
     ) => {
-      module.exports = __webpack_require__(1653);
+      module.exports = __webpack_require__(9025);
 
       /***/
     },
 
-    /***/ 4282: /***/ (
+    /***/ 6236: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -43,7 +26,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(3108);
       /* harmony import */ var next_head__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(3952);
+        __webpack_require__(3770);
       /* harmony import */ var next_head__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_head__WEBPACK_IMPORTED_MODULE_1__
@@ -76,13 +59,30 @@
 
       /***/
     },
+
+    /***/ 6510: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/head",
+        function () {
+          return __webpack_require__(6236);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(1548)
+      __webpack_exec__(6510)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for index-HASH.js
@@ -1,24 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [3332],
   {
-    /***/ 6376: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/",
-        function () {
-          return __webpack_require__(8460);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
-
-    /***/ 8460: /***/ (
+    /***/ 830: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -36,13 +19,30 @@
 
       /***/
     },
+
+    /***/ 1938: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/",
+        function () {
+          return __webpack_require__(830);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(6376)
+      __webpack_exec__(1938)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for link-HASH.js
@@ -1,7 +1,220 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [4672],
   {
-    /***/ 857: /***/ (module, exports, __webpack_require__) => {
+    /***/ 2774: /***/ (module, exports, __webpack_require__) => {
+      "use strict";
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true,
+      });
+      Object.defineProperty(exports, "useIntersection", {
+        enumerable: true,
+        get: function () {
+          return useIntersection;
+        },
+      });
+      const _react = __webpack_require__(4312);
+      const _requestidlecallback = __webpack_require__(9413);
+      const hasIntersectionObserver =
+        typeof IntersectionObserver === "function";
+      const observers = new Map();
+      const idList = [];
+      function createObserver(options) {
+        const id = {
+          root: options.root || null,
+          margin: options.rootMargin || "",
+        };
+        const existing = idList.find(
+          (obj) => obj.root === id.root && obj.margin === id.margin
+        );
+        let instance;
+        if (existing) {
+          instance = observers.get(existing);
+          if (instance) {
+            return instance;
+          }
+        }
+        const elements = new Map();
+        const observer = new IntersectionObserver((entries) => {
+          entries.forEach((entry) => {
+            const callback = elements.get(entry.target);
+            const isVisible =
+              entry.isIntersecting || entry.intersectionRatio > 0;
+            if (callback && isVisible) {
+              callback(isVisible);
+            }
+          });
+        }, options);
+        instance = {
+          id,
+          observer,
+          elements,
+        };
+        idList.push(id);
+        observers.set(id, instance);
+        return instance;
+      }
+      function observe(element, callback, options) {
+        const { id, observer, elements } = createObserver(options);
+        elements.set(element, callback);
+        observer.observe(element);
+        return function unobserve() {
+          elements.delete(element);
+          observer.unobserve(element);
+          // Destroy observer when there's nothing left to watch:
+          if (elements.size === 0) {
+            observer.disconnect();
+            observers.delete(id);
+            const index = idList.findIndex(
+              (obj) => obj.root === id.root && obj.margin === id.margin
+            );
+            if (index > -1) {
+              idList.splice(index, 1);
+            }
+          }
+        };
+      }
+      function useIntersection({ rootRef, rootMargin, disabled }) {
+        const isDisabled = disabled || !hasIntersectionObserver;
+        const [visible, setVisible] = (0, _react.useState)(false);
+        const elementRef = (0, _react.useRef)(null);
+        const setElement = (0, _react.useCallback)((element) => {
+          elementRef.current = element;
+        }, []);
+        (0, _react.useEffect)(() => {
+          if (hasIntersectionObserver) {
+            if (isDisabled || visible) return;
+            const element = elementRef.current;
+            if (element && element.tagName) {
+              const unobserve = observe(
+                element,
+                (isVisible) => isVisible && setVisible(isVisible),
+                {
+                  root: rootRef?.current,
+                  rootMargin,
+                }
+              );
+              return unobserve;
+            }
+          } else {
+            if (!visible) {
+              const idleCallback = (0,
+              _requestidlecallback.requestIdleCallback)(() => setVisible(true));
+              return () =>
+                (0, _requestidlecallback.cancelIdleCallback)(idleCallback);
+            }
+          }
+          // eslint-disable-next-line react-hooks/exhaustive-deps
+        }, [isDisabled, rootMargin, rootRef, visible, elementRef.current]);
+        const resetVisible = (0, _react.useCallback)(() => {
+          setVisible(false);
+        }, []);
+        return [setElement, visible, resetVisible];
+      }
+      if (
+        (typeof exports.default === "function" ||
+          (typeof exports.default === "object" && exports.default !== null)) &&
+        typeof exports.default.__esModule === "undefined"
+      ) {
+        Object.defineProperty(exports.default, "__esModule", {
+          value: true,
+        });
+        Object.assign(exports.default, exports);
+        module.exports = exports.default;
+      } //# sourceMappingURL=use-intersection.js.map
+
+      /***/
+    },
+
+    /***/ 3351: /***/ (module, exports, __webpack_require__) => {
+      "use strict";
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true,
+      });
+      Object.defineProperty(exports, "useMergedRef", {
+        enumerable: true,
+        get: function () {
+          return useMergedRef;
+        },
+      });
+      const _react = __webpack_require__(4312);
+      function useMergedRef(refA, refB) {
+        const cleanupA = (0, _react.useRef)(null);
+        const cleanupB = (0, _react.useRef)(null);
+        // NOTE: In theory, we could skip the wrapping if only one of the refs is non-null.
+        // (this happens often if the user doesn't pass a ref to Link/Form/Image)
+        // But this can cause us to leak a cleanup-ref into user code (previously via `<Link legacyBehavior>`),
+        // and the user might pass that ref into ref-merging library that doesn't support cleanup refs
+        // (because it hasn't been updated for React 19)
+        // which can then cause things to blow up, because a cleanup-returning ref gets called with `null`.
+        // So in practice, it's safer to be defensive and always wrap the ref, even on React 19.
+        return (0, _react.useCallback)(
+          (current) => {
+            if (current === null) {
+              const cleanupFnA = cleanupA.current;
+              if (cleanupFnA) {
+                cleanupA.current = null;
+                cleanupFnA();
+              }
+              const cleanupFnB = cleanupB.current;
+              if (cleanupFnB) {
+                cleanupB.current = null;
+                cleanupFnB();
+              }
+            } else {
+              if (refA) {
+                cleanupA.current = applyRef(refA, current);
+              }
+              if (refB) {
+                cleanupB.current = applyRef(refB, current);
+              }
+            }
+          },
+          [refA, refB]
+        );
+      }
+      function applyRef(refA, current) {
+        if (typeof refA === "function") {
+          const cleanup = refA(current);
+          if (typeof cleanup === "function") {
+            return cleanup;
+          } else {
+            return () => refA(null);
+          }
+        } else {
+          refA.current = current;
+          return () => {
+            refA.current = null;
+          };
+        }
+      }
+      if (
+        (typeof exports.default === "function" ||
+          (typeof exports.default === "object" && exports.default !== null)) &&
+        typeof exports.default.__esModule === "undefined"
+      ) {
+        Object.defineProperty(exports.default, "__esModule", {
+          value: true,
+        });
+        Object.assign(exports.default, exports);
+        module.exports = exports.default;
+      } //# sourceMappingURL=use-merged-ref.js.map
+
+      /***/
+    },
+
+    /***/ 3440: /***/ (
+      module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      module.exports = __webpack_require__(4757);
+
+      /***/
+    },
+
+    /***/ 4757: /***/ (module, exports, __webpack_require__) => {
       "use strict";
       /* __next_internal_client_entry_do_not_use__  cjs */
       Object.defineProperty(exports, "__esModule", {
@@ -23,22 +236,22 @@
           return useLinkStatus;
         },
       });
-      const _interop_require_wildcard = __webpack_require__(8781);
+      const _interop_require_wildcard = __webpack_require__(1162);
       const _jsxruntime = __webpack_require__(3108);
       const _react = /*#__PURE__*/ _interop_require_wildcard._(
         __webpack_require__(4312)
       );
-      const _resolvehref = __webpack_require__(4055);
-      const _islocalurl = __webpack_require__(7175);
-      const _formaturl = __webpack_require__(9674);
-      const _utils = __webpack_require__(7424);
-      const _addlocale = __webpack_require__(589);
-      const _routercontextsharedruntime = __webpack_require__(7010);
-      const _useintersection = __webpack_require__(2330);
-      const _getdomainlocale = __webpack_require__(7207);
-      const _addbasepath = __webpack_require__(9942);
-      const _usemergedref = __webpack_require__(8067);
-      const _erroronce = __webpack_require__(1945);
+      const _resolvehref = __webpack_require__(4691);
+      const _islocalurl = __webpack_require__(4763);
+      const _formaturl = __webpack_require__(3246);
+      const _utils = __webpack_require__(7372);
+      const _addlocale = __webpack_require__(1809);
+      const _routercontextsharedruntime = __webpack_require__(2254);
+      const _useintersection = __webpack_require__(2774);
+      const _getdomainlocale = __webpack_require__(8803);
+      const _addbasepath = __webpack_require__(5834);
+      const _usemergedref = __webpack_require__(3351);
+      const _erroronce = __webpack_require__(6021);
       const prefetched = new Set();
       function prefetch(router, href, as, options) {
         if (false) {
@@ -417,168 +630,43 @@
       /***/
     },
 
-    /***/ 1945: /***/ (__unused_webpack_module, exports) => {
-      "use strict";
-
-      Object.defineProperty(exports, "__esModule", {
-        value: true,
-      });
-      Object.defineProperty(exports, "errorOnce", {
-        enumerable: true,
-        get: function () {
-          return errorOnce;
+    /***/ 5326: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/link",
+        function () {
+          return __webpack_require__(9058);
         },
-      });
-      let errorOnce = (_) => {};
+      ]);
       if (false) {
-      } //# sourceMappingURL=error-once.js.map
+      }
 
       /***/
     },
 
-    /***/ 2330: /***/ (module, exports, __webpack_require__) => {
+    /***/ 6021: /***/ (__unused_webpack_module, exports) => {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
         value: true,
       });
-      Object.defineProperty(exports, "useIntersection", {
+      Object.defineProperty(exports, "errorOnce", {
         enumerable: true,
         get: function () {
-          return useIntersection;
+          return errorOnce;
         },
       });
-      const _react = __webpack_require__(4312);
-      const _requestidlecallback = __webpack_require__(601);
-      const hasIntersectionObserver =
-        typeof IntersectionObserver === "function";
-      const observers = new Map();
-      const idList = [];
-      function createObserver(options) {
-        const id = {
-          root: options.root || null,
-          margin: options.rootMargin || "",
-        };
-        const existing = idList.find(
-          (obj) => obj.root === id.root && obj.margin === id.margin
-        );
-        let instance;
-        if (existing) {
-          instance = observers.get(existing);
-          if (instance) {
-            return instance;
-          }
-        }
-        const elements = new Map();
-        const observer = new IntersectionObserver((entries) => {
-          entries.forEach((entry) => {
-            const callback = elements.get(entry.target);
-            const isVisible =
-              entry.isIntersecting || entry.intersectionRatio > 0;
-            if (callback && isVisible) {
-              callback(isVisible);
-            }
-          });
-        }, options);
-        instance = {
-          id,
-          observer,
-          elements,
-        };
-        idList.push(id);
-        observers.set(id, instance);
-        return instance;
-      }
-      function observe(element, callback, options) {
-        const { id, observer, elements } = createObserver(options);
-        elements.set(element, callback);
-        observer.observe(element);
-        return function unobserve() {
-          elements.delete(element);
-          observer.unobserve(element);
-          // Destroy observer when there's nothing left to watch:
-          if (elements.size === 0) {
-            observer.disconnect();
-            observers.delete(id);
-            const index = idList.findIndex(
-              (obj) => obj.root === id.root && obj.margin === id.margin
-            );
-            if (index > -1) {
-              idList.splice(index, 1);
-            }
-          }
-        };
-      }
-      function useIntersection({ rootRef, rootMargin, disabled }) {
-        const isDisabled = disabled || !hasIntersectionObserver;
-        const [visible, setVisible] = (0, _react.useState)(false);
-        const elementRef = (0, _react.useRef)(null);
-        const setElement = (0, _react.useCallback)((element) => {
-          elementRef.current = element;
-        }, []);
-        (0, _react.useEffect)(() => {
-          if (hasIntersectionObserver) {
-            if (isDisabled || visible) return;
-            const element = elementRef.current;
-            if (element && element.tagName) {
-              const unobserve = observe(
-                element,
-                (isVisible) => isVisible && setVisible(isVisible),
-                {
-                  root: rootRef?.current,
-                  rootMargin,
-                }
-              );
-              return unobserve;
-            }
-          } else {
-            if (!visible) {
-              const idleCallback = (0,
-              _requestidlecallback.requestIdleCallback)(() => setVisible(true));
-              return () =>
-                (0, _requestidlecallback.cancelIdleCallback)(idleCallback);
-            }
-          }
-          // eslint-disable-next-line react-hooks/exhaustive-deps
-        }, [isDisabled, rootMargin, rootRef, visible, elementRef.current]);
-        const resetVisible = (0, _react.useCallback)(() => {
-          setVisible(false);
-        }, []);
-        return [setElement, visible, resetVisible];
-      }
-      if (
-        (typeof exports.default === "function" ||
-          (typeof exports.default === "object" && exports.default !== null)) &&
-        typeof exports.default.__esModule === "undefined"
-      ) {
-        Object.defineProperty(exports.default, "__esModule", {
-          value: true,
-        });
-        Object.assign(exports.default, exports);
-        module.exports = exports.default;
-      } //# sourceMappingURL=use-intersection.js.map
-
-      /***/
-    },
-
-    /***/ 4972: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/link",
-        function () {
-          return __webpack_require__(7600);
-        },
-      ]);
+      let errorOnce = (_) => {};
       if (false) {
-      }
+      } //# sourceMappingURL=error-once.js.map
 
       /***/
     },
 
-    /***/ 7207: /***/ (module, exports, __webpack_require__) => {
+    /***/ 8803: /***/ (module, exports, __webpack_require__) => {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
@@ -590,7 +678,7 @@
           return getDomainLocale;
         },
       });
-      const _normalizetrailingslash = __webpack_require__(151);
+      const _normalizetrailingslash = __webpack_require__(1315);
       const basePath =
         /* unused pure expression or super */ null && (false || "");
       function getDomainLocale(path, locale, locales, domainLocales) {
@@ -614,7 +702,7 @@
       /***/
     },
 
-    /***/ 7600: /***/ (
+    /***/ 9058: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -629,7 +717,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(3108);
       /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(7830);
+        __webpack_require__(3440);
       /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_link__WEBPACK_IMPORTED_MODULE_1__
@@ -659,101 +747,13 @@
 
       /***/
     },
-
-    /***/ 7830: /***/ (
-      module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      module.exports = __webpack_require__(857);
-
-      /***/
-    },
-
-    /***/ 8067: /***/ (module, exports, __webpack_require__) => {
-      "use strict";
-
-      Object.defineProperty(exports, "__esModule", {
-        value: true,
-      });
-      Object.defineProperty(exports, "useMergedRef", {
-        enumerable: true,
-        get: function () {
-          return useMergedRef;
-        },
-      });
-      const _react = __webpack_require__(4312);
-      function useMergedRef(refA, refB) {
-        const cleanupA = (0, _react.useRef)(null);
-        const cleanupB = (0, _react.useRef)(null);
-        // NOTE: In theory, we could skip the wrapping if only one of the refs is non-null.
-        // (this happens often if the user doesn't pass a ref to Link/Form/Image)
-        // But this can cause us to leak a cleanup-ref into user code (previously via `<Link legacyBehavior>`),
-        // and the user might pass that ref into ref-merging library that doesn't support cleanup refs
-        // (because it hasn't been updated for React 19)
-        // which can then cause things to blow up, because a cleanup-returning ref gets called with `null`.
-        // So in practice, it's safer to be defensive and always wrap the ref, even on React 19.
-        return (0, _react.useCallback)(
-          (current) => {
-            if (current === null) {
-              const cleanupFnA = cleanupA.current;
-              if (cleanupFnA) {
-                cleanupA.current = null;
-                cleanupFnA();
-              }
-              const cleanupFnB = cleanupB.current;
-              if (cleanupFnB) {
-                cleanupB.current = null;
-                cleanupFnB();
-              }
-            } else {
-              if (refA) {
-                cleanupA.current = applyRef(refA, current);
-              }
-              if (refB) {
-                cleanupB.current = applyRef(refB, current);
-              }
-            }
-          },
-          [refA, refB]
-        );
-      }
-      function applyRef(refA, current) {
-        if (typeof refA === "function") {
-          const cleanup = refA(current);
-          if (typeof cleanup === "function") {
-            return cleanup;
-          } else {
-            return () => refA(null);
-          }
-        } else {
-          refA.current = current;
-          return () => {
-            refA.current = null;
-          };
-        }
-      }
-      if (
-        (typeof exports.default === "function" ||
-          (typeof exports.default === "object" && exports.default !== null)) &&
-        typeof exports.default.__esModule === "undefined"
-      ) {
-        Object.defineProperty(exports.default, "__esModule", {
-          value: true,
-        });
-        Object.assign(exports.default, exports);
-        module.exports = exports.default;
-      } //# sourceMappingURL=use-merged-ref.js.map
-
-      /***/
-    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(4972)
+      __webpack_exec__(5326)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for routerDirect-HASH.js
@@ -1,17 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [188],
   {
-    /***/ 1179: /***/ (
-      module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      module.exports = __webpack_require__(9864);
-
-      /***/
-    },
-
-    /***/ 1640: /***/ (
+    /***/ 2014: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -26,7 +16,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(3108);
       /* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(1179);
+        __webpack_require__(4169);
       /* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_router__WEBPACK_IMPORTED_MODULE_1__
@@ -46,7 +36,17 @@
       /***/
     },
 
-    /***/ 2172: /***/ (
+    /***/ 4169: /***/ (
+      module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      module.exports = __webpack_require__(9700);
+
+      /***/
+    },
+
+    /***/ 4414: /***/ (
       __unused_webpack_module,
       __unused_webpack_exports,
       __webpack_require__
@@ -54,7 +54,7 @@
       (window.__NEXT_P = window.__NEXT_P || []).push([
         "/routerDirect",
         function () {
-          return __webpack_require__(1640);
+          return __webpack_require__(2014);
         },
       ]);
       if (false) {
@@ -68,7 +68,7 @@
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(2172)
+      __webpack_exec__(4414)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for script-HASH.js
@@ -1,17 +1,34 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [1209],
   {
-    /***/ 4977: /***/ (
+    /***/ 2591: /***/ (
       module,
       __unused_webpack_exports,
       __webpack_require__
     ) => {
-      module.exports = __webpack_require__(326);
+      module.exports = __webpack_require__(4634);
 
       /***/
     },
 
-    /***/ 5887: /***/ (
+    /***/ 5030: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/script",
+        function () {
+          return __webpack_require__(7557);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
+
+    /***/ 7557: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -26,7 +43,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(3108);
       /* harmony import */ var next_script__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(4977);
+        __webpack_require__(2591);
       /* harmony import */ var next_script__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_script__WEBPACK_IMPORTED_MODULE_1__
@@ -58,30 +75,13 @@
 
       /***/
     },
-
-    /***/ 6268: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/script",
-        function () {
-          return __webpack_require__(5887);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(6268)
+      __webpack_exec__(5030)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for withRouter-HASH.js
@@ -1,34 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [3263],
   {
-    /***/ 1179: /***/ (
-      module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      module.exports = __webpack_require__(9864);
-
-      /***/
-    },
-
-    /***/ 2028: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/withRouter",
-        function () {
-          return __webpack_require__(4501);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
-
-    /***/ 4501: /***/ (
+    /***/ 559: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -43,7 +16,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(3108);
       /* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(1179);
+        __webpack_require__(4169);
       /* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_router__WEBPACK_IMPORTED_MODULE_1__
@@ -61,13 +34,40 @@
 
       /***/
     },
+
+    /***/ 726: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/withRouter",
+        function () {
+          return __webpack_require__(559);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
+
+    /***/ 4169: /***/ (
+      module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      module.exports = __webpack_require__(9700);
+
+      /***/
+    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(2028)
+      __webpack_exec__(726)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for 2161-HASH.js

Diff too large to display

Diff for 2747-HASH.js

Diff too large to display

Diff for 4322-HASH.js
failed to diff
Diff for main-HASH.js

Diff too large to display

Diff for main-app-HASH.js
@@ -1,64 +1,64 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [4977],
   {
-    /***/ 341: /***/ () => {
-      /* (ignored) */
-      /***/
-    },
-
-    /***/ 5544: /***/ (
+    /***/ 1052: /***/ (
       __unused_webpack_module,
       __unused_webpack_exports,
       __webpack_require__
     ) => {
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 375, 23)
+        __webpack_require__.t.bind(__webpack_require__, 7413, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 2972, 23)
+        __webpack_require__.t.bind(__webpack_require__, 9898, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 7508, 23)
+        __webpack_require__.t.bind(__webpack_require__, 9854, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 6043, 23)
+        __webpack_require__.t.bind(__webpack_require__, 9261, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 9797, 23)
+        __webpack_require__.t.bind(__webpack_require__, 867, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 2933, 23)
+        __webpack_require__.t.bind(__webpack_require__, 2463, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 4220, 23)
+        __webpack_require__.t.bind(__webpack_require__, 1866, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 97, 23)
+        __webpack_require__.t.bind(__webpack_require__, 9667, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 464, 23)
+        __webpack_require__.t.bind(__webpack_require__, 8822, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 619, 23)
+        __webpack_require__.t.bind(__webpack_require__, 1717, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 1464, 23)
+        __webpack_require__.t.bind(__webpack_require__, 5366, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.bind(__webpack_require__, 5297)
+        __webpack_require__.bind(__webpack_require__, 1155)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 7937, 23)
+        __webpack_require__.t.bind(__webpack_require__, 391, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 7584, 23)
+        __webpack_require__.t.bind(__webpack_require__, 7346, 23)
       );
       Promise.resolve(/* import() eager */).then(
-        __webpack_require__.t.bind(__webpack_require__, 6826, 23)
+        __webpack_require__.t.bind(__webpack_require__, 1340, 23)
       );
 
       /***/
     },
+
+    /***/ 2751: /***/ () => {
+      /* (ignored) */
+      /***/
+    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
@@ -66,8 +66,8 @@
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(
       0,
-      [5639, 4322],
-      () => (__webpack_exec__(2193), __webpack_exec__(5544))
+      [8580, 2658],
+      () => (__webpack_exec__(9851), __webpack_exec__(1052))
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Commit: 23d82bf

@feedthejim feedthejim force-pushed the perf-cpu-profiling branch 2 times, most recently from 86cd290 to 23d82bf Compare January 5, 2026 13:56
@nextjs-bot
Copy link
Collaborator

nextjs-bot commented Jan 5, 2026

Stats from current PR

Default Build (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
buildDuration 17.4s 14.9s N/A
buildDurationCached 13.8s 10.9s N/A
nodeModulesSize 457 MB 457 MB ⚠️ +49.4 kB
nextStartRea..uration (ms) 717ms 714ms N/A
Client Bundles (main, webpack) Overall increase ⚠️
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
2086.HASH.js gzip 169 B 169 B
2161-HASH.js gzip 5.39 kB 5.41 kB N/A
2747-HASH.js gzip 4.48 kB 4.46 kB N/A
4322-HASH.js gzip 52.5 kB 52.2 kB N/A
ec793fe8-HASH.js gzip 62.3 kB 62.3 kB N/A
framework-HASH.js gzip 59.8 kB 59.8 kB N/A
main-app-HASH.js gzip 252 B 254 B N/A
main-HASH.js gzip 38.4 kB 38.7 kB ⚠️ +368 B
webpack-HASH.js gzip 1.68 kB 1.69 kB N/A
Overall change 38.5 kB 38.9 kB ⚠️ +368 B
Legacy Client Bundles (polyfills)
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
polyfills-HASH.js gzip 39.4 kB 39.4 kB
Overall change 39.4 kB 39.4 kB
Client Pages
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
_app-HASH.js gzip 194 B 193 B N/A
_error-HASH.js gzip 182 B 182 B
css-HASH.js gzip 336 B 335 B N/A
dynamic-HASH.js gzip 1.8 kB 1.8 kB N/A
edge-ssr-HASH.js gzip 256 B 256 B
head-HASH.js gzip 352 B 349 B N/A
hooks-HASH.js gzip 385 B 384 B N/A
image-HASH.js gzip 580 B 580 B
index-HASH.js gzip 259 B 258 B N/A
link-HASH.js gzip 2.5 kB 2.51 kB N/A
routerDirect..HASH.js gzip 319 B 317 B N/A
script-HASH.js gzip 385 B 387 B N/A
withRouter-HASH.js gzip 316 B 315 B N/A
1afbb74e6ecf..834.css gzip 106 B 106 B
Overall change 1.12 kB 1.12 kB
Client Build Manifests
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
_buildManifest.js gzip 738 B 738 B
Overall change 738 B 738 B
Rendered Page Sizes
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
index.html gzip 523 B 525 B N/A
link.html gzip 537 B 539 B N/A
withRouter.html gzip 520 B 521 B N/A
Overall change 0 B 0 B
Edge SSR bundle Size Overall increase ⚠️
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
edge-ssr.js gzip 124 kB 124 kB N/A
page.js gzip 238 kB 239 kB ⚠️ +664 B
Overall change 238 kB 239 kB ⚠️ +664 B
Middleware size Overall increase ⚠️
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
middleware-b..fest.js gzip 649 B 656 B N/A
middleware-r..fest.js gzip 155 B 156 B N/A
middleware.js gzip 32.6 kB 32.9 kB ⚠️ +344 B
edge-runtime..pack.js gzip 846 B 846 B
Overall change 33.4 kB 33.7 kB ⚠️ +344 B
Next Runtimes
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
app-page-exp...dev.js gzip 302 kB 302 kB N/A
app-page-exp..prod.js gzip 157 kB 157 kB
app-page-tur...dev.js gzip 302 kB 302 kB N/A
app-page-tur..prod.js gzip 157 kB 157 kB
app-page-tur...dev.js gzip 299 kB 299 kB
app-page-tur..prod.js gzip 155 kB 155 kB
app-page.run...dev.js gzip 299 kB 299 kB N/A
app-page.run..prod.js gzip 155 kB 155 kB
app-route-ex...dev.js gzip 68.7 kB 68.7 kB
app-route-ex..prod.js gzip 47.5 kB 47.5 kB
app-route-tu...dev.js gzip 68.7 kB 68.7 kB
app-route-tu..prod.js gzip 47.5 kB 47.5 kB
app-route-tu...dev.js gzip 68.3 kB 68.3 kB
app-route-tu..prod.js gzip 47.3 kB 47.3 kB
app-route.ru...dev.js gzip 68.3 kB 68.3 kB
app-route.ru..prod.js gzip 47.3 kB 47.3 kB
dist_client_...dev.js gzip 324 B 324 B
dist_client_...dev.js gzip 326 B 326 B
dist_client_...dev.js gzip 318 B 318 B
dist_client_...dev.js gzip 317 B 317 B
pages-api-tu...dev.js gzip 41.1 kB 41.1 kB
pages-api-tu..prod.js gzip 31.2 kB 31.2 kB
pages-api.ru...dev.js gzip 41 kB 41 kB
pages-api.ru..prod.js gzip 31.2 kB 31.2 kB
pages-turbo....dev.js gzip 50.7 kB 50.7 kB
pages-turbo...prod.js gzip 38.2 kB 38.2 kB
pages.runtim...dev.js gzip 50.6 kB 50.6 kB
pages.runtim..prod.js gzip 38.1 kB 38.1 kB
server.runti..prod.js gzip 59.9 kB 59.9 kB
Overall change 1.77 MB 1.77 MB
build cache Overall increase ⚠️
vercel/next.js canary vercel/next.js perf-cpu-profiling Change
0.pack gzip 3.62 MB 3.62 MB ⚠️ +1.61 kB
index.pack gzip 99.4 kB 98.5 kB N/A
Overall change 3.62 MB 3.62 MB ⚠️ +1.61 kB
Diff details
Diff for page.js

Diff too large to display

Diff for middleware.js

Diff too large to display

Diff for edge-ssr.js

Diff too large to display

Diff for _buildManifest.js
@@ -611,35 +611,35 @@ self.__BUILD_MANIFEST = (function (a, b, c) {
       numHashes: NaN,
       bitArray: [],
     },
-    "/": ["static\u002Fchunks\u002Fpages\u002Findex-dda7d8b64d4ba15c.js"],
+    "/": ["static\u002Fchunks\u002Fpages\u002Findex-d95f7ec6af4d2644.js"],
     "/_error": [
-      "static\u002Fchunks\u002Fpages\u002F_error-6ef44d3954f25711.js",
+      "static\u002Fchunks\u002Fpages\u002F_error-209c0c82205a7c9f.js",
     ],
     "/css": [
       "static\u002Fcss\u002Fded6b86ab9cc0a1f.css",
-      "static\u002Fchunks\u002Fpages\u002Fcss-c8aaa7211416a045.js",
+      "static\u002Fchunks\u002Fpages\u002Fcss-62710339bc830ded.js",
     ],
     "/dynamic": [
-      "static\u002Fchunks\u002Fpages\u002Fdynamic-d53bb7f318f342c2.js",
+      "static\u002Fchunks\u002Fpages\u002Fdynamic-8ed3486bb68dd6c6.js",
     ],
     "/edge-ssr": [
-      "static\u002Fchunks\u002Fpages\u002Fedge-ssr-1383106d4a3e7d72.js",
+      "static\u002Fchunks\u002Fpages\u002Fedge-ssr-0db9f7bb610d3072.js",
     ],
-    "/head": ["static\u002Fchunks\u002Fpages\u002Fhead-1db1c4be1a45662f.js"],
-    "/hooks": ["static\u002Fchunks\u002Fpages\u002Fhooks-e6deee5b72a5b112.js"],
+    "/head": ["static\u002Fchunks\u002Fpages\u002Fhead-747416c4075e42aa.js"],
+    "/hooks": ["static\u002Fchunks\u002Fpages\u002Fhooks-8b10205be7505244.js"],
     "/image": [
-      "static\u002Fchunks\u002F2747-90c828280005c0c3.js",
-      "static\u002Fchunks\u002Fpages\u002Fimage-868472cd5e84efc9.js",
+      "static\u002Fchunks\u002F6349-ee9aecde860d4832.js",
+      "static\u002Fchunks\u002Fpages\u002Fimage-f90ae17c3ad1d38b.js",
     ],
-    "/link": ["static\u002Fchunks\u002Fpages\u002Flink-0ec374e48b2ce5d9.js"],
+    "/link": ["static\u002Fchunks\u002Fpages\u002Flink-6ab9a67b348df1bf.js"],
     "/routerDirect": [
-      "static\u002Fchunks\u002Fpages\u002FrouterDirect-1a34bfadbc088491.js",
+      "static\u002Fchunks\u002Fpages\u002FrouterDirect-f132fb471e65a8b9.js",
     ],
     "/script": [
-      "static\u002Fchunks\u002Fpages\u002Fscript-52320f59afbd096d.js",
+      "static\u002Fchunks\u002Fpages\u002Fscript-8e2028e44b8da2d9.js",
     ],
     "/withRouter": [
-      "static\u002Fchunks\u002Fpages\u002FwithRouter-3b1a16d3dfa21c16.js",
+      "static\u002Fchunks\u002Fpages\u002FwithRouter-a86d259faa012c1c.js",
     ],
     sortedPages: [
       "\u002F",
Diff for dynamic-HASH.js
@@ -1,17 +1,24 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [2291],
   {
-    /***/ 1231: /***/ (
-      module,
+    /***/ 2604: /***/ (
+      __unused_webpack_module,
       __unused_webpack_exports,
       __webpack_require__
     ) => {
-      module.exports = __webpack_require__(4464);
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/dynamic",
+        function () {
+          return __webpack_require__(3643);
+        },
+      ]);
+      if (false) {
+      }
 
       /***/
     },
 
-    /***/ 2101: /***/ (
+    /***/ 3401: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -38,24 +45,63 @@
       /***/
     },
 
-    /***/ 3458: /***/ (
+    /***/ 3643: /***/ (
       __unused_webpack_module,
-      __unused_webpack_exports,
+      __webpack_exports__,
       __webpack_require__
     ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/dynamic",
-        function () {
-          return __webpack_require__(9381);
-        },
-      ]);
-      if (false) {
-      }
+      "use strict";
+      __webpack_require__.r(__webpack_exports__);
+      /* harmony export */ __webpack_require__.d(__webpack_exports__, {
+        /* harmony export */ __N_SSP: () => /* binding */ __N_SSP,
+        /* harmony export */ default: () => __WEBPACK_DEFAULT_EXPORT__,
+        /* harmony export */
+      });
+      /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
+        __webpack_require__(3108);
+      /* harmony import */ var next_dynamic__WEBPACK_IMPORTED_MODULE_1__ =
+        __webpack_require__(3973);
+      /* harmony import */ var next_dynamic__WEBPACK_IMPORTED_MODULE_1___default =
+        /*#__PURE__*/ __webpack_require__.n(
+          next_dynamic__WEBPACK_IMPORTED_MODULE_1__
+        );
+
+      const DynamicHello = next_dynamic__WEBPACK_IMPORTED_MODULE_1___default()(
+        () =>
+          __webpack_require__
+            .e(/* import() */ 1596)
+            .then(__webpack_require__.bind(__webpack_require__, 1596))
+            .then((mod) => mod.Hello),
+        {
+          loadableGenerated: {
+            webpack: () => [/*require.resolve*/ 1596],
+          },
+        }
+      );
+      const Page = () =>
+        /*#__PURE__*/ (0, react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(
+          react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment,
+          {
+            children: [
+              /*#__PURE__*/ (0,
+              react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
+                children: "testing next/dynamic size",
+              }),
+              /*#__PURE__*/ (0,
+              react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(
+                DynamicHello,
+                {}
+              ),
+            ],
+          }
+        );
+      var __N_SSP = true;
+      /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = Page;
 
       /***/
     },
 
-    /***/ 4464: /***/ (module, exports, __webpack_require__) => {
+    /***/ 3660: /***/ (module, exports, __webpack_require__) => {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
@@ -88,7 +134,7 @@
         __webpack_require__(4312)
       );
       const _loadablesharedruntime = /*#__PURE__*/ _interop_require_default._(
-        __webpack_require__(9799)
+        __webpack_require__(4539)
       );
       const isServerSide = "object" === "undefined";
       // Normalize loader to return the module as form { default: Component } for `React.lazy`.
@@ -188,63 +234,17 @@
       /***/
     },
 
-    /***/ 9381: /***/ (
-      __unused_webpack_module,
-      __webpack_exports__,
+    /***/ 3973: /***/ (
+      module,
+      __unused_webpack_exports,
       __webpack_require__
     ) => {
-      "use strict";
-      __webpack_require__.r(__webpack_exports__);
-      /* harmony export */ __webpack_require__.d(__webpack_exports__, {
-        /* harmony export */ __N_SSP: () => /* binding */ __N_SSP,
-        /* harmony export */ default: () => __WEBPACK_DEFAULT_EXPORT__,
-        /* harmony export */
-      });
-      /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
-        __webpack_require__(3108);
-      /* harmony import */ var next_dynamic__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(1231);
-      /* harmony import */ var next_dynamic__WEBPACK_IMPORTED_MODULE_1___default =
-        /*#__PURE__*/ __webpack_require__.n(
-          next_dynamic__WEBPACK_IMPORTED_MODULE_1__
-        );
-
-      const DynamicHello = next_dynamic__WEBPACK_IMPORTED_MODULE_1___default()(
-        () =>
-          __webpack_require__
-            .e(/* import() */ 2086)
-            .then(__webpack_require__.bind(__webpack_require__, 2086))
-            .then((mod) => mod.Hello),
-        {
-          loadableGenerated: {
-            webpack: () => [/*require.resolve*/ 2086],
-          },
-        }
-      );
-      const Page = () =>
-        /*#__PURE__*/ (0, react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(
-          react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment,
-          {
-            children: [
-              /*#__PURE__*/ (0,
-              react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
-                children: "testing next/dynamic size",
-              }),
-              /*#__PURE__*/ (0,
-              react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(
-                DynamicHello,
-                {}
-              ),
-            ],
-          }
-        );
-      var __N_SSP = true;
-      /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = Page;
+      module.exports = __webpack_require__(3660);
 
       /***/
     },
 
-    /***/ 9799: /***/ (
+    /***/ 4539: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -286,7 +286,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
       const _react = /*#__PURE__*/ _interop_require_default._(
         __webpack_require__(4312)
       );
-      const _loadablecontextsharedruntime = __webpack_require__(2101);
+      const _loadablecontextsharedruntime = __webpack_require__(3401);
       function resolve(obj) {
         return obj && obj.default ? obj.default : obj;
       }
@@ -524,7 +524,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(3458)
+      __webpack_exec__(2604)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for edge-ssr-HASH.js
@@ -1,7 +1,24 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [676],
   {
-    /***/ 1564: /***/ (
+    /***/ 7046: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/edge-ssr",
+        function () {
+          return __webpack_require__(7142);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
+
+    /***/ 7142: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -20,30 +37,13 @@
 
       /***/
     },
-
-    /***/ 4300: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/edge-ssr",
-        function () {
-          return __webpack_require__(1564);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(4300)
+      __webpack_exec__(7046)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for head-HASH.js
@@ -1,34 +1,17 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [5350],
   {
-    /***/ 1548: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/head",
-        function () {
-          return __webpack_require__(4282);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
-
-    /***/ 3952: /***/ (
+    /***/ 3770: /***/ (
       module,
       __unused_webpack_exports,
       __webpack_require__
     ) => {
-      module.exports = __webpack_require__(1653);
+      module.exports = __webpack_require__(9025);
 
       /***/
     },
 
-    /***/ 4282: /***/ (
+    /***/ 6236: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -43,7 +26,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(3108);
       /* harmony import */ var next_head__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(3952);
+        __webpack_require__(3770);
       /* harmony import */ var next_head__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_head__WEBPACK_IMPORTED_MODULE_1__
@@ -76,13 +59,30 @@
 
       /***/
     },
+
+    /***/ 6510: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/head",
+        function () {
+          return __webpack_require__(6236);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(1548)
+      __webpack_exec__(6510)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for index-HASH.js
@@ -1,24 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [3332],
   {
-    /***/ 6376: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/",
-        function () {
-          return __webpack_require__(8460);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
-
-    /***/ 8460: /***/ (
+    /***/ 830: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -36,13 +19,30 @@
 
       /***/
     },
+
+    /***/ 1938: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/",
+        function () {
+          return __webpack_require__(830);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(6376)
+      __webpack_exec__(1938)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for link-HASH.js
@@ -1,7 +1,220 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [4672],
   {
-    /***/ 857: /***/ (module, exports, __webpack_require__) => {
+    /***/ 2774: /***/ (module, exports, __webpack_require__) => {
+      "use strict";
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true,
+      });
+      Object.defineProperty(exports, "useIntersection", {
+        enumerable: true,
+        get: function () {
+          return useIntersection;
+        },
+      });
+      const _react = __webpack_require__(4312);
+      const _requestidlecallback = __webpack_require__(9413);
+      const hasIntersectionObserver =
+        typeof IntersectionObserver === "function";
+      const observers = new Map();
+      const idList = [];
+      function createObserver(options) {
+        const id = {
+          root: options.root || null,
+          margin: options.rootMargin || "",
+        };
+        const existing = idList.find(
+          (obj) => obj.root === id.root && obj.margin === id.margin
+        );
+        let instance;
+        if (existing) {
+          instance = observers.get(existing);
+          if (instance) {
+            return instance;
+          }
+        }
+        const elements = new Map();
+        const observer = new IntersectionObserver((entries) => {
+          entries.forEach((entry) => {
+            const callback = elements.get(entry.target);
+            const isVisible =
+              entry.isIntersecting || entry.intersectionRatio > 0;
+            if (callback && isVisible) {
+              callback(isVisible);
+            }
+          });
+        }, options);
+        instance = {
+          id,
+          observer,
+          elements,
+        };
+        idList.push(id);
+        observers.set(id, instance);
+        return instance;
+      }
+      function observe(element, callback, options) {
+        const { id, observer, elements } = createObserver(options);
+        elements.set(element, callback);
+        observer.observe(element);
+        return function unobserve() {
+          elements.delete(element);
+          observer.unobserve(element);
+          // Destroy observer when there's nothing left to watch:
+          if (elements.size === 0) {
+            observer.disconnect();
+            observers.delete(id);
+            const index = idList.findIndex(
+              (obj) => obj.root === id.root && obj.margin === id.margin
+            );
+            if (index > -1) {
+              idList.splice(index, 1);
+            }
+          }
+        };
+      }
+      function useIntersection({ rootRef, rootMargin, disabled }) {
+        const isDisabled = disabled || !hasIntersectionObserver;
+        const [visible, setVisible] = (0, _react.useState)(false);
+        const elementRef = (0, _react.useRef)(null);
+        const setElement = (0, _react.useCallback)((element) => {
+          elementRef.current = element;
+        }, []);
+        (0, _react.useEffect)(() => {
+          if (hasIntersectionObserver) {
+            if (isDisabled || visible) return;
+            const element = elementRef.current;
+            if (element && element.tagName) {
+              const unobserve = observe(
+                element,
+                (isVisible) => isVisible && setVisible(isVisible),
+                {
+                  root: rootRef?.current,
+                  rootMargin,
+                }
+              );
+              return unobserve;
+            }
+          } else {
+            if (!visible) {
+              const idleCallback = (0,
+              _requestidlecallback.requestIdleCallback)(() => setVisible(true));
+              return () =>
+                (0, _requestidlecallback.cancelIdleCallback)(idleCallback);
+            }
+          }
+          // eslint-disable-next-line react-hooks/exhaustive-deps
+        }, [isDisabled, rootMargin, rootRef, visible, elementRef.current]);
+        const resetVisible = (0, _react.useCallback)(() => {
+          setVisible(false);
+        }, []);
+        return [setElement, visible, resetVisible];
+      }
+      if (
+        (typeof exports.default === "function" ||
+          (typeof exports.default === "object" && exports.default !== null)) &&
+        typeof exports.default.__esModule === "undefined"
+      ) {
+        Object.defineProperty(exports.default, "__esModule", {
+          value: true,
+        });
+        Object.assign(exports.default, exports);
+        module.exports = exports.default;
+      } //# sourceMappingURL=use-intersection.js.map
+
+      /***/
+    },
+
+    /***/ 3351: /***/ (module, exports, __webpack_require__) => {
+      "use strict";
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true,
+      });
+      Object.defineProperty(exports, "useMergedRef", {
+        enumerable: true,
+        get: function () {
+          return useMergedRef;
+        },
+      });
+      const _react = __webpack_require__(4312);
+      function useMergedRef(refA, refB) {
+        const cleanupA = (0, _react.useRef)(null);
+        const cleanupB = (0, _react.useRef)(null);
+        // NOTE: In theory, we could skip the wrapping if only one of the refs is non-null.
+        // (this happens often if the user doesn't pass a ref to Link/Form/Image)
+        // But this can cause us to leak a cleanup-ref into user code (previously via `<Link legacyBehavior>`),
+        // and the user might pass that ref into ref-merging library that doesn't support cleanup refs
+        // (because it hasn't been updated for React 19)
+        // which can then cause things to blow up, because a cleanup-returning ref gets called with `null`.
+        // So in practice, it's safer to be defensive and always wrap the ref, even on React 19.
+        return (0, _react.useCallback)(
+          (current) => {
+            if (current === null) {
+              const cleanupFnA = cleanupA.current;
+              if (cleanupFnA) {
+                cleanupA.current = null;
+                cleanupFnA();
+              }
+              const cleanupFnB = cleanupB.current;
+              if (cleanupFnB) {
+                cleanupB.current = null;
+                cleanupFnB();
+              }
+            } else {
+              if (refA) {
+                cleanupA.current = applyRef(refA, current);
+              }
+              if (refB) {
+                cleanupB.current = applyRef(refB, current);
+              }
+            }
+          },
+          [refA, refB]
+        );
+      }
+      function applyRef(refA, current) {
+        if (typeof refA === "function") {
+          const cleanup = refA(current);
+          if (typeof cleanup === "function") {
+            return cleanup;
+          } else {
+            return () => refA(null);
+          }
+        } else {
+          refA.current = current;
+          return () => {
+            refA.current = null;
+          };
+        }
+      }
+      if (
+        (typeof exports.default === "function" ||
+          (typeof exports.default === "object" && exports.default !== null)) &&
+        typeof exports.default.__esModule === "undefined"
+      ) {
+        Object.defineProperty(exports.default, "__esModule", {
+          value: true,
+        });
+        Object.assign(exports.default, exports);
+        module.exports = exports.default;
+      } //# sourceMappingURL=use-merged-ref.js.map
+
+      /***/
+    },
+
+    /***/ 3440: /***/ (
+      module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      module.exports = __webpack_require__(4757);
+
+      /***/
+    },
+
+    /***/ 4757: /***/ (module, exports, __webpack_require__) => {
       "use strict";
       /* __next_internal_client_entry_do_not_use__  cjs */
       Object.defineProperty(exports, "__esModule", {
@@ -23,22 +236,22 @@
           return useLinkStatus;
         },
       });
-      const _interop_require_wildcard = __webpack_require__(8781);
+      const _interop_require_wildcard = __webpack_require__(1162);
       const _jsxruntime = __webpack_require__(3108);
       const _react = /*#__PURE__*/ _interop_require_wildcard._(
         __webpack_require__(4312)
       );
-      const _resolvehref = __webpack_require__(4055);
-      const _islocalurl = __webpack_require__(7175);
-      const _formaturl = __webpack_require__(9674);
-      const _utils = __webpack_require__(7424);
-      const _addlocale = __webpack_require__(589);
-      const _routercontextsharedruntime = __webpack_require__(7010);
-      const _useintersection = __webpack_require__(2330);
-      const _getdomainlocale = __webpack_require__(7207);
-      const _addbasepath = __webpack_require__(9942);
-      const _usemergedref = __webpack_require__(8067);
-      const _erroronce = __webpack_require__(1945);
+      const _resolvehref = __webpack_require__(4691);
+      const _islocalurl = __webpack_require__(4763);
+      const _formaturl = __webpack_require__(3246);
+      const _utils = __webpack_require__(7372);
+      const _addlocale = __webpack_require__(1809);
+      const _routercontextsharedruntime = __webpack_require__(2254);
+      const _useintersection = __webpack_require__(2774);
+      const _getdomainlocale = __webpack_require__(8803);
+      const _addbasepath = __webpack_require__(5834);
+      const _usemergedref = __webpack_require__(3351);
+      const _erroronce = __webpack_require__(6021);
       const prefetched = new Set();
       function prefetch(router, href, as, options) {
         if (false) {
@@ -417,168 +630,43 @@
       /***/
     },
 
-    /***/ 1945: /***/ (__unused_webpack_module, exports) => {
-      "use strict";
-
-      Object.defineProperty(exports, "__esModule", {
-        value: true,
-      });
-      Object.defineProperty(exports, "errorOnce", {
-        enumerable: true,
-        get: function () {
-          return errorOnce;
+    /***/ 5326: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/link",
+        function () {
+          return __webpack_require__(9058);
         },
-      });
-      let errorOnce = (_) => {};
+      ]);
       if (false) {
-      } //# sourceMappingURL=error-once.js.map
+      }
 
       /***/
     },
 
-    /***/ 2330: /***/ (module, exports, __webpack_require__) => {
+    /***/ 6021: /***/ (__unused_webpack_module, exports) => {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
         value: true,
       });
-      Object.defineProperty(exports, "useIntersection", {
+      Object.defineProperty(exports, "errorOnce", {
         enumerable: true,
         get: function () {
-          return useIntersection;
+          return errorOnce;
         },
       });
-      const _react = __webpack_require__(4312);
-      const _requestidlecallback = __webpack_require__(601);
-      const hasIntersectionObserver =
-        typeof IntersectionObserver === "function";
-      const observers = new Map();
-      const idList = [];
-      function createObserver(options) {
-        const id = {
-          root: options.root || null,
-          margin: options.rootMargin || "",
-        };
-        const existing = idList.find(
-          (obj) => obj.root === id.root && obj.margin === id.margin
-        );
-        let instance;
-        if (existing) {
-          instance = observers.get(existing);
-          if (instance) {
-            return instance;
-          }
-        }
-        const elements = new Map();
-        const observer = new IntersectionObserver((entries) => {
-          entries.forEach((entry) => {
-            const callback = elements.get(entry.target);
-            const isVisible =
-              entry.isIntersecting || entry.intersectionRatio > 0;
-            if (callback && isVisible) {
-              callback(isVisible);
-            }
-          });
-        }, options);
-        instance = {
-          id,
-          observer,
-          elements,
-        };
-        idList.push(id);
-        observers.set(id, instance);
-        return instance;
-      }
-      function observe(element, callback, options) {
-        const { id, observer, elements } = createObserver(options);
-        elements.set(element, callback);
-        observer.observe(element);
-        return function unobserve() {
-          elements.delete(element);
-          observer.unobserve(element);
-          // Destroy observer when there's nothing left to watch:
-          if (elements.size === 0) {
-            observer.disconnect();
-            observers.delete(id);
-            const index = idList.findIndex(
-              (obj) => obj.root === id.root && obj.margin === id.margin
-            );
-            if (index > -1) {
-              idList.splice(index, 1);
-            }
-          }
-        };
-      }
-      function useIntersection({ rootRef, rootMargin, disabled }) {
-        const isDisabled = disabled || !hasIntersectionObserver;
-        const [visible, setVisible] = (0, _react.useState)(false);
-        const elementRef = (0, _react.useRef)(null);
-        const setElement = (0, _react.useCallback)((element) => {
-          elementRef.current = element;
-        }, []);
-        (0, _react.useEffect)(() => {
-          if (hasIntersectionObserver) {
-            if (isDisabled || visible) return;
-            const element = elementRef.current;
-            if (element && element.tagName) {
-              const unobserve = observe(
-                element,
-                (isVisible) => isVisible && setVisible(isVisible),
-                {
-                  root: rootRef?.current,
-                  rootMargin,
-                }
-              );
-              return unobserve;
-            }
-          } else {
-            if (!visible) {
-              const idleCallback = (0,
-              _requestidlecallback.requestIdleCallback)(() => setVisible(true));
-              return () =>
-                (0, _requestidlecallback.cancelIdleCallback)(idleCallback);
-            }
-          }
-          // eslint-disable-next-line react-hooks/exhaustive-deps
-        }, [isDisabled, rootMargin, rootRef, visible, elementRef.current]);
-        const resetVisible = (0, _react.useCallback)(() => {
-          setVisible(false);
-        }, []);
-        return [setElement, visible, resetVisible];
-      }
-      if (
-        (typeof exports.default === "function" ||
-          (typeof exports.default === "object" && exports.default !== null)) &&
-        typeof exports.default.__esModule === "undefined"
-      ) {
-        Object.defineProperty(exports.default, "__esModule", {
-          value: true,
-        });
-        Object.assign(exports.default, exports);
-        module.exports = exports.default;
-      } //# sourceMappingURL=use-intersection.js.map
-
-      /***/
-    },
-
-    /***/ 4972: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/link",
-        function () {
-          return __webpack_require__(7600);
-        },
-      ]);
+      let errorOnce = (_) => {};
       if (false) {
-      }
+      } //# sourceMappingURL=error-once.js.map
 
       /***/
     },
 
-    /***/ 7207: /***/ (module, exports, __webpack_require__) => {
+    /***/ 8803: /***/ (module, exports, __webpack_require__) => {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
@@ -590,7 +678,7 @@
           return getDomainLocale;
         },
       });
-      const _normalizetrailingslash = __webpack_require__(151);
+      const _normalizetrailingslash = __webpack_require__(1315);
       const basePath =
         /* unused pure expression or super */ null && (false || "");
       function getDomainLocale(path, locale, locales, domainLocales) {
@@ -614,7 +702,7 @@
       /***/
     },
 
-    /***/ 7600: /***/ (
+    /***/ 9058: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -629,7 +717,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(3108);
       /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(7830);
+        __webpack_require__(3440);
       /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_link__WEBPACK_IMPORTED_MODULE_1__
@@ -659,101 +747,13 @@
 
       /***/
     },
-
-    /***/ 7830: /***/ (
-      module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      module.exports = __webpack_require__(857);
-
-      /***/
-    },
-
-    /***/ 8067: /***/ (module, exports, __webpack_require__) => {
-      "use strict";
-
-      Object.defineProperty(exports, "__esModule", {
-        value: true,
-      });
-      Object.defineProperty(exports, "useMergedRef", {
-        enumerable: true,
-        get: function () {
-          return useMergedRef;
-        },
-      });
-      const _react = __webpack_require__(4312);
-      function useMergedRef(refA, refB) {
-        const cleanupA = (0, _react.useRef)(null);
-        const cleanupB = (0, _react.useRef)(null);
-        // NOTE: In theory, we could skip the wrapping if only one of the refs is non-null.
-        // (this happens often if the user doesn't pass a ref to Link/Form/Image)
-        // But this can cause us to leak a cleanup-ref into user code (previously via `<Link legacyBehavior>`),
-        // and the user might pass that ref into ref-merging library that doesn't support cleanup refs
-        // (because it hasn't been updated for React 19)
-        // which can then cause things to blow up, because a cleanup-returning ref gets called with `null`.
-        // So in practice, it's safer to be defensive and always wrap the ref, even on React 19.
-        return (0, _react.useCallback)(
-          (current) => {
-            if (current === null) {
-              const cleanupFnA = cleanupA.current;
-              if (cleanupFnA) {
-                cleanupA.current = null;
-                cleanupFnA();
-              }
-              const cleanupFnB = cleanupB.current;
-              if (cleanupFnB) {
-                cleanupB.current = null;
-                cleanupFnB();
-              }
-            } else {
-              if (refA) {
-                cleanupA.current = applyRef(refA, current);
-              }
-              if (refB) {
-                cleanupB.current = applyRef(refB, current);
-              }
-            }
-          },
-          [refA, refB]
-        );
-      }
-      function applyRef(refA, current) {
-        if (typeof refA === "function") {
-          const cleanup = refA(current);
-          if (typeof cleanup === "function") {
-            return cleanup;
-          } else {
-            return () => refA(null);
-          }
-        } else {
-          refA.current = current;
-          return () => {
-            refA.current = null;
-          };
-        }
-      }
-      if (
-        (typeof exports.default === "function" ||
-          (typeof exports.default === "object" && exports.default !== null)) &&
-        typeof exports.default.__esModule === "undefined"
-      ) {
-        Object.defineProperty(exports.default, "__esModule", {
-          value: true,
-        });
-        Object.assign(exports.default, exports);
-        module.exports = exports.default;
-      } //# sourceMappingURL=use-merged-ref.js.map
-
-      /***/
-    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(4972)
+      __webpack_exec__(5326)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for routerDirect-HASH.js
@@ -1,17 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [188],
   {
-    /***/ 1179: /***/ (
-      module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      module.exports = __webpack_require__(9864);
-
-      /***/
-    },
-
-    /***/ 1640: /***/ (
+    /***/ 2014: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -26,7 +16,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(3108);
       /* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(1179);
+        __webpack_require__(4169);
       /* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_router__WEBPACK_IMPORTED_MODULE_1__
@@ -46,7 +36,17 @@
       /***/
     },
 
-    /***/ 2172: /***/ (
+    /***/ 4169: /***/ (
+      module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      module.exports = __webpack_require__(9700);
+
+      /***/
+    },
+
+    /***/ 4414: /***/ (
       __unused_webpack_module,
       __unused_webpack_exports,
       __webpack_require__
@@ -54,7 +54,7 @@
       (window.__NEXT_P = window.__NEXT_P || []).push([
         "/routerDirect",
         function () {
-          return __webpack_require__(1640);
+          return __webpack_require__(2014);
         },
       ]);
       if (false) {
@@ -68,7 +68,7 @@
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(2172)
+      __webpack_exec__(4414)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for script-HASH.js
@@ -1,17 +1,34 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [1209],
   {
-    /***/ 4977: /***/ (
+    /***/ 2591: /***/ (
       module,
       __unused_webpack_exports,
       __webpack_require__
     ) => {
-      module.exports = __webpack_require__(326);
+      module.exports = __webpack_require__(4634);
 
       /***/
     },
 
-    /***/ 5887: /***/ (
+    /***/ 5030: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/script",
+        function () {
+          return __webpack_require__(7557);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
+
+    /***/ 7557: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -26,7 +43,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(3108);
       /* harmony import */ var next_script__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(4977);
+        __webpack_require__(2591);
       /* harmony import */ var next_script__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_script__WEBPACK_IMPORTED_MODULE_1__
@@ -58,30 +75,13 @@
 
       /***/
     },
-
-    /***/ 6268: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/script",
-        function () {
-          return __webpack_require__(5887);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(6268)
+      __webpack_exec__(5030)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for withRouter-HASH.js
@@ -1,34 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [3263],
   {
-    /***/ 1179: /***/ (
-      module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      module.exports = __webpack_require__(9864);
-
-      /***/
-    },
-
-    /***/ 2028: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/withRouter",
-        function () {
-          return __webpack_require__(4501);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
-
-    /***/ 4501: /***/ (
+    /***/ 559: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -43,7 +16,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(3108);
       /* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(1179);
+        __webpack_require__(4169);
       /* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_router__WEBPACK_IMPORTED_MODULE_1__
@@ -61,13 +34,40 @@
 
       /***/
     },
+
+    /***/ 726: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/withRouter",
+        function () {
+          return __webpack_require__(559);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
+
+    /***/ 4169: /***/ (
+      module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      module.exports = __webpack_require__(9700);
+
+      /***/
+    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(2028)
+      __webpack_exec__(726)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for 2161-HASH.js

Diff too large to display

Diff for 2747-HASH.js

Diff too large to display

Diff for 4322-HASH.js
failed to diff
Diff for main-HASH.js

Diff too large to display

Commit: 39efa9d

Comment on lines +17 to +19
process.on('exit', () => {
saveCpuProfile()
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exit event only allows synchronous operations. However, fs.writeFileSync on line 61 is called inside a callback from session.post() (line 38). If this callback is asynchronous, the file write will not complete before process exit. The comment claims synchronous execution but Node.js inspector callbacks may not guarantee this in all cases, especially under load.

// Consider using fs.writeFileSync synchronously outside the callback:
const result = session.postSync('Profiler.stop')
if (!result.error) {
  fs.writeFileSync(outputPath, JSON.stringify(result.profile))
}
// Or document this limitation clearly if async behavior is unavoidable
Suggested change
process.on('exit', () => {
saveCpuProfile()
})
process.on('exit', () => {
// Use synchronous operations only in exit handlers
try {
const session = profiler?.session
if (session && profiler?.isEnabled) {
const result = session.postSync('Profiler.stop')
if (!result.error && profiler.outputPath) {
fs.writeFileSync(profiler.outputPath, JSON.stringify(result.profile))
}
}
} catch (err) {
console.error('Failed to save CPU profile on exit:', err)
}
})

Spotted by Graphite Agent

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

* Save the CPU profile to disk.
*
* This is synchronous despite the callback-based API because inspector's
* session.post() executes its callback synchronously when connected to
Copy link
Contributor

@vercel vercel bot Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saveCpuProfile() declared as returning void but awaited in multiple places - type signature should match usage pattern.

View Details
📝 Patch Details
diff --git a/packages/next/src/server/lib/cpu-profile.ts b/packages/next/src/server/lib/cpu-profile.ts
index 9420e7a7c0..bd8d74f1d0 100644
--- a/packages/next/src/server/lib/cpu-profile.ts
+++ b/packages/next/src/server/lib/cpu-profile.ts
@@ -26,42 +26,46 @@ if (isCpuProfileEnabled) {
  * session.post() executes its callback synchronously when connected to
  * the same process (via session.connect()).
  */
-export function saveCpuProfile(): void {
+export function saveCpuProfile(): Promise<void> {
   if (!session || profileSaved || !isCpuProfileEnabled) {
-    return
+    return Promise.resolve()
   }
   profileSaved = true
 
   const fs = require('fs') as typeof import('fs')
   const path = require('path') as typeof import('path')
 
-  session!.post('Profiler.stop', (error, param) => {
-    if (error) {
-      console.error('Cannot generate CPU profiling:', error)
-      return
-    }
+  return new Promise<void>((resolve) => {
+    session!.post('Profiler.stop', (error, param) => {
+      if (error) {
+        console.error('Cannot generate CPU profiling:', error)
+        resolve()
+        return
+      }
 
-    const timestamp = new Date()
-      .toISOString()
-      .replace(/[:.]/g, '-')
-      .slice(0, 19)
-    const baseName = privateCpuProfileName || 'cpu-profile'
-    const filename = `${baseName}-${timestamp}.cpuprofile`
+      const timestamp = new Date()
+        .toISOString()
+        .replace(/[:.]/g, '-')
+        .slice(0, 19)
+      const baseName = privateCpuProfileName || 'cpu-profile'
+      const filename = `${baseName}-${timestamp}.cpuprofile`
 
-    let outputPath: string
-    if (cpuProfileDir) {
-      if (!fs.existsSync(cpuProfileDir)) {
-        fs.mkdirSync(cpuProfileDir, { recursive: true })
+      let outputPath: string
+      if (cpuProfileDir) {
+        if (!fs.existsSync(cpuProfileDir)) {
+          fs.mkdirSync(cpuProfileDir, { recursive: true })
+        }
+        outputPath = path.join(cpuProfileDir, filename)
+      } else {
+        outputPath = `./${filename}`
       }
-      outputPath = path.join(cpuProfileDir, filename)
-    } else {
-      outputPath = `./${filename}`
-    }
 
-    fs.writeFileSync(outputPath, JSON.stringify(param.profile))
-    const { green } =
-      require('../../lib/picocolors') as typeof import('../../lib/picocolors')
-    console.log(`\n${green('CPU profile saved:')} ${outputPath}`)
-    console.log('Open in Chrome DevTools → Performance tab → Load profile')
+      fs.writeFileSync(outputPath, JSON.stringify(param.profile))
+      const { green } =
+        require('../../lib/picocolors') as typeof import('../../lib/picocolors')
+      console.log(`\n${green('CPU profile saved:')} ${outputPath}`)
+      console.log('Open in Chrome DevTools → Performance tab → Load profile')
+      resolve()
+    })
   })
 }

Analysis

Issue Details

The saveCpuProfile() function in packages/next/src/server/lib/cpu-profile.ts was declared as returning void, but was being awaited in multiple places:

  • packages/next/src/build/webpack-build/impl.ts line 422: await saveCpuProfile()
  • packages/next/src/build/turbopack-build/impl.ts line 267: await saveCpuProfile()
  • packages/next/src/bin/next.ts: await mod.saveCpuProfile()

This created a type mismatch: the function signature suggested it doesn't return anything useful, but callers were treating it as an asynchronous operation that needed to be awaited.

Why This Was a Bug (Despite Working)

  1. Type Safety Violation: The void return type is misleading when the function is being awaited
  2. Code Clarity: It's unclear from the signature whether the function is synchronous or asynchronous
  3. Fragility: If the inspector implementation changed or code was refactored, the lack of a proper Promise wrapper would hide async issues
  4. TypeScript Expectations: While TypeScript allows awaiting non-Promise values, it's considered an anti-pattern

Why It Worked

The function actually completes synchronously because:

  • The Node.js inspector.Session.post() method executes callbacks synchronously when the session is connected to the same process via session.connect()
  • The file write using fs.writeFileSync() happens synchronously in the callback
  • So the work completes before the function returns, even though it's declared as void

The Fix

Changed the return type from void to Promise<void>:

  1. Wrapped the callback-based code in a proper Promise that resolves when the work completes
  2. Returns Promise.resolve() for early exit cases
  3. The Promise resolves synchronously (matching the actual behavior) but now provides proper type safety
  4. All calling patterns continue to work:
    • await saveCpuProfile() works correctly with proper async semantics
    • saveCpuProfile() without await still works (the returned Promise is just ignored)
    • process.on('exit', () => saveCpuProfile()) works (calling Promise-returning function without await is valid)

This fix ensures type safety, code clarity, and maintainability while preserving the actual behavior of the code.

Fix on Vercel

@timneutkens timneutkens merged commit fd5817d into canary Jan 7, 2026
163 checks passed
@timneutkens timneutkens deleted the perf-cpu-profiling branch January 7, 2026 10:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI Bypass Graphite Optimization Ignore Graphite CI optimizations, run the full CI suite. https://graphite.dev/docs/stacking-and-ci created-by: Next.js team PRs by the Next.js team. Documentation Related to Next.js' official documentation. tests type: next

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants