mirror of
https://github.com/vercel/next.js.git
synced 2026-09-20 02:25:18 +08:00
cb0d88f6e3
<!-- CURSOR_AGENT_PR_BODY_BEGIN --> ### What? Improves the error message shown when a user tries to start `next dev` while another dev server is already running in the same directory. ### Why? Previously, the error message only suggested killing the existing process (`Run kill <pid> to stop it.`). This wasn't the best advice — often the user just wants to access the already-running dev server rather than kill it and start a new one. ### How? Updated the error message in `packages/next/src/build/lockfile.ts` to present both options: 1. Access the existing server at its URL 2. Kill the process if they want to start a new one **Before:** ``` ✖ Another next dev server is already running. - Local: http://localhost:3000 - PID: 61479 - Dir: /path/to/project - Log: .next/dev/logs/next-development.log Run kill 61479 to stop it. ``` **After:** ``` ✖ Another next dev server is already running. - Local: http://localhost:3000 - PID: 61479 - Dir: /path/to/project - Log: .next/dev/logs/next-development.log You can access the existing server at http://localhost:3000, or run kill 61479 to stop it and start a new one. ``` Updated the lockfile test regex to match the new message format. <!-- CURSOR_AGENT_PR_BODY_END --> [Slack Thread](https://vercel.slack.com/archives/C046HAU4H7F/p1775173304387809?thread_ts=1775173304.387809&cid=C046HAU4H7F) <div><a href="https://cursor.com/agents/bc-0bb3085b-1fd1-56c3-8617-cd8a32d8c376"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-0bb3085b-1fd1-56c3-8617-cd8a32d8c376"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
72 lines
2.4 KiB
TypeScript
72 lines
2.4 KiB
TypeScript
import { nextTestSetup } from 'e2e-utils'
|
|
import execa from 'execa'
|
|
import fs from 'fs'
|
|
import path from 'path'
|
|
import stripAnsi from 'strip-ansi'
|
|
|
|
describe('lockfile', () => {
|
|
const { next, isTurbopack, isRspack } = nextTestSetup({
|
|
files: __dirname,
|
|
})
|
|
|
|
it('only allows a single instance of `next dev` to run at a time', async () => {
|
|
const browser = await next.browser('/')
|
|
expect(await browser.elementByCss('p').text()).toBe('Page')
|
|
|
|
// Verify lockfile was created with server info inside it
|
|
// With isolatedDevBuild (default), distDir is .next/dev
|
|
const distDir = path.join(next.testDir, '.next', 'dev')
|
|
const lockfilePath = path.join(distDir, 'lock')
|
|
expect(fs.existsSync(lockfilePath)).toBe(true)
|
|
|
|
// Read server info from the lockfile itself
|
|
const serverInfo = JSON.parse(fs.readFileSync(lockfilePath, 'utf-8'))
|
|
expect(serverInfo).toMatchObject({
|
|
pid: expect.any(Number),
|
|
port: expect.any(Number),
|
|
hostname: expect.any(String),
|
|
appUrl: expect.any(String),
|
|
startedAt: expect.any(Number),
|
|
})
|
|
|
|
// Try to start another dev server - should fail with helpful error
|
|
const { stdout, stderr, exitCode } = await execa(
|
|
'pnpm',
|
|
[
|
|
'next',
|
|
'dev',
|
|
...(isRspack ? [] : [isTurbopack ? '--turbopack' : '--webpack']),
|
|
],
|
|
{
|
|
cwd: next.testDir,
|
|
env: next.env as NodeJS.ProcessEnv,
|
|
reject: false,
|
|
}
|
|
)
|
|
|
|
const output = stripAnsi(stdout + stderr)
|
|
|
|
// Match the whole error message pattern with fuzzy matching for dynamic parts
|
|
// The kill command varies by platform: `kill <pid>` on Unix, `taskkill /PID <pid> /F` on Windows
|
|
const killPattern =
|
|
process.platform === 'win32'
|
|
? 'or run taskkill /PID \\d+ /F to stop it and start a new one\\.'
|
|
: 'or run kill \\d+ to stop it and start a new one\\.'
|
|
const errorPattern = new RegExp(
|
|
'Another next dev server is already running\\.\\s*' +
|
|
'- Local:\\s+http://[^\\s]+\\s+' +
|
|
'- PID:\\s+\\d+\\s+' +
|
|
'- Dir:\\s+[^\\s]+\\s+' +
|
|
'- Log:\\s+\\.next/dev/logs/next-development\\.log\\s+' +
|
|
'You can access the existing server at http://[^\\s]+,\\s+' +
|
|
killPattern
|
|
)
|
|
expect(output).toMatch(errorPattern)
|
|
expect(exitCode).toBe(1)
|
|
|
|
// Make sure the other instance of `next dev` didn't mess anything up
|
|
await browser.refresh()
|
|
expect(await browser.elementByCss('p').text()).toBe('Page')
|
|
})
|
|
})
|