Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow port 0 in next dev and next start #40118

Merged
merged 3 commits into from Aug 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 5 additions & 10 deletions packages/next/cli/next-dev.ts
Expand Up @@ -2,7 +2,7 @@
import arg from 'next/dist/compiled/arg/index.js'
import { existsSync, watchFile } from 'fs'
import { startServer } from '../server/lib/start-server'
import { printAndExit } from '../server/lib/utils'
import { getPort, printAndExit } from '../server/lib/utils'
import * as Log from '../build/output/log'
import { startedDevelopmentServer } from '../build/output'
import { cliCommand } from '../lib/commands'
Expand Down Expand Up @@ -75,16 +75,11 @@ const nextDev: cliCommand = (argv) => {
)
}
}
const allowRetry = !args['--port']
let port: number =
args['--port'] || (process.env.PORT && parseInt(process.env.PORT)) || 3000

// we allow the server to use a random port while testing
// instead of attempting to find a random port and then hope
// it doesn't become occupied before we leverage it
if (process.env.__NEXT_FORCED_PORT) {
port = parseInt(process.env.__NEXT_FORCED_PORT, 10) || 0
}
const port = getPort(args)
// If neither --port nor PORT were specified, it's okay to retry new ports.
const allowRetry =
args['--port'] === undefined && process.env.PORT === undefined
Copy link
Member Author

Choose a reason for hiding this comment

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

This brings next dev in line with next start: when PORT is present, it won't retry.


// We do not set a default host value here to prevent breaking
// some set-ups that rely on listening on other interfaces
Expand Down
9 changes: 2 additions & 7 deletions packages/next/cli/next-start.ts
Expand Up @@ -2,7 +2,7 @@

import arg from 'next/dist/compiled/arg/index.js'
import { startServer } from '../server/lib/start-server'
import { printAndExit } from '../server/lib/utils'
import { getPort, printAndExit } from '../server/lib/utils'
import * as Log from '../build/output/log'
import isError from '../lib/is-error'
import { getProjectDir } from '../lib/get-project-dir'
Expand Down Expand Up @@ -52,13 +52,8 @@ const nextStart: cliCommand = (argv) => {
}

const dir = getProjectDir(args._[0])
let port: number =
args['--port'] || (process.env.PORT && parseInt(process.env.PORT)) || 3000
const host = args['--hostname'] || '0.0.0.0'

if (process.env.__NEXT_FORCED_PORT) {
port = parseInt(process.env.__NEXT_FORCED_PORT, 10) || 0
}
const port = getPort(args)

const keepAliveTimeoutArg: number | undefined = args['--keepAliveTimeout']
if (
Expand Down
15 changes: 15 additions & 0 deletions packages/next/server/lib/utils.ts
@@ -1,3 +1,5 @@
import type arg from 'next/dist/compiled/arg/index.js'

export function printAndExit(message: string, code = 1) {
if (code === 0) {
console.log(message)
Expand All @@ -12,3 +14,16 @@ export function getNodeOptionsWithoutInspect() {
const NODE_INSPECT_RE = /--inspect(-brk)?(=\S+)?( |$)/
return (process.env.NODE_OPTIONS || '').replace(NODE_INSPECT_RE, '')
}

export function getPort(args: arg.Result<arg.Spec>): number {
if (typeof args['--port'] === 'number') {
return args['--port']
}

const parsed = process.env.PORT && parseInt(process.env.PORT, 10)
if (typeof parsed === 'number' && !Number.isNaN(parsed)) {
return parsed
}

return 3000
}
28 changes: 28 additions & 0 deletions test/integration/cli/test/index.test.js
Expand Up @@ -178,6 +178,34 @@ describe('CLI Usage', () => {
expect(output).toMatch(new RegExp(`http://localhost:${port}`))
})

test('--port 0', async () => {
const output = await runNextCommandDev([dir, '--port', '0'], true)
const matches = /on 0.0.0.0:(\d+)/.exec(output)
expect(matches).not.toBe(null)

const port = parseInt(matches[1])
// Regression test: port 0 was interpreted as if no port had been
// provided, falling back to 3000.
expect(port).not.toBe(3000)

expect(output).toMatch(new RegExp(`http://localhost:${port}`))
})

test('PORT=0', async () => {
const output = await runNextCommandDev([dir], true, {
env: { PORT: 0 },
})
const matches = /on 0.0.0.0:(\d+)/.exec(output)
expect(matches).not.toBe(null)

const port = parseInt(matches[1])
// Regression test: port 0 was interpreted as if no port had been
// provided, falling back to 3000.
expect(port).not.toBe(3000)

expect(output).toMatch(new RegExp(`http://localhost:${port}`))
})

test("NODE_OPTIONS='--inspect'", async () => {
// this test checks that --inspect works by launching a single debugger for the main Next.js process,
// not for its subprocesses
Expand Down
2 changes: 1 addition & 1 deletion test/lib/next-modes/next-dev.ts
Expand Up @@ -37,8 +37,8 @@ export class NextDevInstance extends NextInstance {
...process.env,
...this.env,
NODE_ENV: '' as any,
PORT: this.forcedPort || '0',
__NEXT_TEST_MODE: '1',
__NEXT_FORCED_PORT: this.forcedPort || '0',
__NEXT_TEST_WITH_DEVTOOL: '1',
},
})
Expand Down
2 changes: 1 addition & 1 deletion test/lib/next-modes/next-start.ts
Expand Up @@ -48,8 +48,8 @@ export class NextStartInstance extends NextInstance {
...process.env,
...this.env,
NODE_ENV: '' as any,
PORT: this.forcedPort || '0',
__NEXT_TEST_MODE: '1',
__NEXT_FORCED_PORT: this.forcedPort || '0',
},
}
let buildArgs = ['yarn', 'next', 'build']
Expand Down