Files
2026-10-08 11:34:12 +08:00

50 lines
1.8 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* 启动文档站 dev server,启动前挑一个真正空闲的端口。
*
* 为什么不用 Nuxt 自带的端口回退:Nuxt 靠“试绑 host”判断端口是否空闲,而 Windows 上 Node
* 默认开启 SO_REUSEADDR,**允许多个进程绑定同一个 addr:port**,于是“能不能绑上”根本判断不出
* 冲突 —— 3000 已被别的服务占用时,探测仍然成功,Nuxt 就继续用 3000。
*
* 因此这里改用“实际建立 TCP 连接”来判断:只要 127.0.0.1 或 ::1 任一能连上,就说明该端口
* 正在被监听(可覆盖占用方绑在 0.0.0.0 / 127.0.0.1 / ::1 的所有常见情况),然后依次向上找。
*
* 起始端口:DOCS_PORT > PORT > 3000。
*/
import { spawn } from 'node:child_process'
import { connect } from 'node:net'
const start = Number(process.env.DOCS_PORT || process.env.PORT || 3000)
const MAX_TRIES = 100
/** 能否连接到 host:port(能连上即为“正在被监听”) */
function reachable(port, host) {
return new Promise((resolve) => {
const socket = connect({ port, host })
const done = (busy) => {
socket.destroy()
resolve(busy)
}
socket.setTimeout(400)
socket.once('connect', () => done(true))
socket.once('timeout', () => done(false))
socket.once('error', () => done(false))
})
}
async function isBusy(port) {
const [v4, v6] = await Promise.all([reachable(port, '127.0.0.1'), reachable(port, '::1')])
return v4 || v6
}
let port = start
while (port < start + MAX_TRIES && (await isBusy(port))) port++
if (port !== start) console.log(`端口 ${start} 已被占用,改用 ${port}`)
const child = spawn('nuxt', ['dev', '--port', String(port)], {
stdio: 'inherit',
shell: true,
})
child.on('exit', (code) => process.exit(code ?? 0))