From ae64e15b31ec2e252771665ca32220dfbd2d1068 Mon Sep 17 00:00:00 2001 From: Hendrik Liebau Date: Wed, 13 Nov 2024 16:57:14 +0100 Subject: [PATCH] Re-use randomly selected dev server port for automatic restarts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When `next dev` is started with `-p 0` or `PORT=0` – which is probably unusual in userland, but is the default for our tests – a random port is selected for the dev server. If the user, after starting the dev server, then changes the `next.config.js` file, the dev server detects that and automatically restarts. For the restart, the original port config is used, resulting in a random port being selected again. This will most likely be a different port as was selected before, and so reloads in the browser won't work. It also results in `ERR_CONNECTION_REFUSED` errors in our tests that use `patchFile` to change the `next.config.js` content. To fix that issue, we're now storing the automatically selected port when the dev server has started initially, and are re-using it for any subsequent automatic restarts. --- packages/next/src/cli/next-dev.ts | 11 +++++++++-- packages/next/src/server/lib/start-server.ts | 7 +++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/next/src/cli/next-dev.ts b/packages/next/src/cli/next-dev.ts index af8f8a7e9f9ad..99f49294525a5 100644 --- a/packages/next/src/cli/next-dev.ts +++ b/packages/next/src/cli/next-dev.ts @@ -206,7 +206,7 @@ const nextDev = async ( } } - const port = options.port + let port = options.port if (isPortIsReserved(port)) { printAndExit(getReservedPortExplanation(port), 1) @@ -299,6 +299,12 @@ const nextDev = async ( if (msg.nextWorkerReady) { child?.send({ nextWorkerOptions: startServerOptions }) } else if (msg.nextServerReady && !resolved) { + if (msg.port) { + // Store the used port in case a random one was selected, so that + // it can be re-used on automatic dev server restarts. + port = parseInt(msg.port, 10) + } + resolved = true resolve() } @@ -323,7 +329,8 @@ const nextDev = async ( sync: true, }) } - return startServer(startServerOptions) + + return startServer({ ...startServerOptions, port }) } // Call handler (e.g. upload telemetry). Don't try to send a signal to // the child, as it has already exited. diff --git a/packages/next/src/server/lib/start-server.ts b/packages/next/src/server/lib/start-server.ts index fcd7fd338eba7..c427a0fc82e68 100644 --- a/packages/next/src/server/lib/start-server.ts +++ b/packages/next/src/server/lib/start-server.ts @@ -255,8 +255,11 @@ export async function startServer( ) } - // expose the main port to render workers + // Store the selected port to: + // - expose it to render workers + // - re-use it for automatic dev server restarts with a randomly selected port process.env.PORT = port + '' + process.env.__NEXT_PRIVATE_ORIGIN = appUrl // Only load env and config in dev to for logging purposes @@ -420,7 +423,7 @@ if (process.env.NEXT_PRIVATE_WORKER && process.send) { 'memory.heapUsed', String(memoryUsage.heapUsed) ) - process.send({ nextServerReady: true }) + process.send({ nextServerReady: true, port: process.env.PORT }) } }) process.send({ nextWorkerReady: true })