📌 项目地址:vercel-labs/portless | ⭐ 11,613 颗星 | 🔧 TypeScript | 📜 未标注

问题:端口号在本地开发里到处添堵

同时跑几个项目的人都知道这些摩擦:localhost:3000、localhost:5173、localhost:8080,靠数字区分应用,记不住,还经常被占用。更实际的问题是浏览器对 localhost 和真实域名的处理不一致——secure cookie、Service Worker、混合内容拦截,在裸 localhost 上根本测不出真实行为。

vercel-labs 的 portless(TypeScript,11613 stars)给的方案是给每个本地应用一个稳定的命名域名:

- "dev": "next dev"                  # http://localhost:3000
+ "dev": "portless run next dev"     # https://myapp.localhost

域名就是应用名,HTTPS 和 HTTP/2 默认开启。

五分钟上手

全局安装(README 推荐):

npm install -g portless

或者装进项目:

npm install -D portless

运行:

portless myapp next dev
# -> https://myapp.localhost

首次运行时,portless 生成本地 CA、把它加入信任、绑定 443 端口(macOS/Linux 上自动 sudo 提权)。不需要 TLS 就加 --no-tls。

一个提醒值得写进 README 原话:项目还没到 1.0。装在项目里时,不同贡献者可能跑不同版本;状态目录格式可能随版本变化,需要重新执行 portless trust。

端口分配的机制

proxy 随命令自动启动,给应用分配 4000–4999 之间的随机端口,通过 PORT 环境变量传入。Next.js、Express、Nuxt 这类框架会自动读取。

麻烦在忽略 PORT 的框架:Vite、VitePlus、Astro、React Router、Angular、Expo、React Native。portless 对这类框架直接注入对应的 --port flag,必要时再补 --host。注入能穿透 package script——只要命令以框架名或已知 runner 开头,"dev": "vite" 和 "dev": "bunx vite" 都能识别。

我最欣赏的部分:注入的克制

自动改写用户的命令是危险操作,改错了轻则报错,重则构建产物出错。portless 在这里划的边界很细。

只动真正的服务器命令。 dev、serve、preview、start、裸的 vite 或 vite [root] 会拿到注入的端口。vite build、vite optimize、vp test、astro check 这些不接受端口参数的命令,会被识别出来然后原样放过。

看不懂就不碰。 这些情况全部跳过注入:

  • 子命令前有它不认识的 flag(vp --mode dev build)
  • 复合命令(&&、|、;)
  • 尾部带 # 注释,或自带 -- 终结符
  • env 前缀(NODE_ENV=production vite)
  • 委托给其他脚本("dev": "npm run dev:vite")
  • runner flag 在脚本名前面(bun run --bun dev)

这些命令保留自己的端口,由用户自己去脚本里设置。Expo 的连接模式(--localhost、--lan、--tunnel)会被保留,同时照常注入分配的端口。

这套”宁可不做,也不做错”的清单,说明作者认真想过失败模式。对一个要改写用户命令的工具,这是能不能被信任的分界线。

配置持久化与 CI 行为

三个细节值得单独说。

代理自动启动时,会复用最近一次运行的配置(端口、TLS、TLDs),重启机器后不会静默回退默认值。显式环境变量(PORTLESS_PORT、PORTLESS_HTTPS 等)永远优先。

状态存在 ~/.portless。代理在 sudo 下运行时,这个路径会从发起用户的 home 解析,这样代理和普通权限的应用进程能共享同一套路由注册——一个容易踩的坑被提前处理了。

无 TTY 或 CI=1 的环境里,portless 直接带描述性错误退出,不卡在交互提示上。turborepo 这类任务运行器和 CI 脚本能尽早失败,错误信息是可读的。

“For humans and agents”

README 副标题里写了 agents。端口号对 AI 编程代理是真实的痛点:端口变了、被占了、和验证脚本对不上,代理只能去猜或重试。稳定的 https://myapp.localhost 让代理每次都用同一个 URL 验证开发服务器,不需要先探测端口。加上 HTTPS 默认开启,代理也不会被 self-signed 证书的报错卡住。

对一个还没到 1.0 的工具来说,11613 颗星说明这个痛点足够普遍。如果你本地常年开着三五个 dev server,值得装一个试试。

这篇文章对你有帮助吗?

发表回复