Repository: vercel/next.js
File: packages/next/src/build/lockfile.ts (TypeScript)

Code before:
import fs from 'fs'
import nodePath from 'path'
import { bold, cyan } from '../lib/picocolors'
import * as Log from './output/log'
import { getBindingsSync } from './swc'

import type { Binding, Lockfile as NativeLockfile } from './swc/types'

const RETRY_DELAY_MS = 10
const MAX_RETRY_MS = 1000

// File name for storing dev server info alongside the lock
const DEV_SERVER_INFO_FILE = 'dev-server-info.json'

/**
 * Information about a running dev server, stored alongside the lock file.
 */
export interface DevServerInfo {
  pid: number
  port: number
  hostname: string
  appUrl: string
  startedAt: number
}

/**
 * Writes dev server info to a file in the dist directory.
 * This allows other processes to discover the running server when lock acquisition fails.
 */
export function writeDevServerInfo(distDir: string, info: DevServerInfo): void {
  try {
    fs.writeFileSync(
      nodePath.join(distDir, DEV_SERVER_INFO_FILE),
      JSON.stringify(info, null, 2)
    )
  } catch {
    // Ignore errors - this is best effort
  }

Review comment (suggestion):
Optional: It should be possible to store this information in the lockfile itself. You can modify the lockfile API to accept an optional string or buffer that it can write to the file when it creates it.

That'll require a tiny bit of Rust code, so feel free to ping me if you run into problems, but it should be pretty straightforward.

It's very common for \*nix applications to store information inside of a lockfile, usually a pid.

- On \*nix platforms it's an advisory lock, which doesn't prevent you from reading it. You only observe the lock if you explicitly check for it (with the `flock` or `fcntl` syscalls). Most \*nix platforms (including Linux and macOS) do not have a way of doing mandatory locks.
- Most locks on Windows are mandatory locks, but we use `FILE_SHARE_READ | FILE_SHARE_DELETE` (excluding the default `FILE_SHARE_WRITE` flag), which allows other processes to read (but not write to) the lockfile. I did it this way so that we could store information in the lockfile. https://github.com/vercel/next.js/blob/11e295089c5759891b82168c2cf7153731704519/crates/napi/src/lockfile.rs#L46



Code after:
import fs from 'fs'
import nodePath from 'path'
import { bold, cyan } from '../lib/picocolors'
import * as Log from './output/log'
import { getBindingsSync } from './swc'

import type { Binding, Lockfile as NativeLockfile } from './swc/types'

const RETRY_DELAY_MS = 10
const MAX_RETRY_MS = 1000

/**
 * Information about a running dev server, stored inside the lock file itself.
 * This is a common pattern in Unix applications (e.g., storing PID in a lockfile).
 */
export interface DevServerInfo {
  pid: number
  port: number
  hostname: string
  appUrl: string
  startedAt: number
}

/**
 * Reads dev server info from a lockfile.
 * Returns undefined if the file doesn't exist or can't be parsed.
 *
 * Uses Node's fs.readFileSync which works on both Unix (with advisory flock)
 * and Windows (with FILE_SHARE_READ flag set by the lock holder).
 */
export function readLockfileContent(lockfilePath: string): string | undefined {
  try {
    return fs.readFileSync(lockfilePath, 'utf-8')
  } catch {
    return undefined
  }
}