Skip to content

Commit

Permalink
Allow port 0 in next dev and next start
Browse files Browse the repository at this point in the history
Co-authored-by: Steven <steven@ceriously.com>
  • Loading branch information
wbinnssmith and styfle committed Aug 31, 2022
1 parent b522b94 commit bf96626
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 19 deletions.
14 changes: 4 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,10 @@ 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'] === null && process.env.PORT === null

// 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 (args['--port'] != null) {
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

0 comments on commit bf96626

Please sign in to comment.