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

端口号是本地开发的历史遗留问题

跑多个项目的人对这个场景不陌生:localhost:3000localhost:5173localhost:8080,全靠端口号区分。端口记错、被占用、换了分支就变了,是日常摩擦。更麻烦的是浏览器对 localhost 和真实域名的待遇不一样——secure cookie、Service Worker、混合内容拦截这些行为,本地默认测不到真实情况。

portless(vercel-labs 出品,TypeScript,11613 颗星)的做法是给每个本地应用一个稳定的命名域名:

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

域名即应用名。HTTPS + HTTP/2 默认开启,本地就能测 TLS 相关行为。

上手

npm install -g portless

或装到项目里:

npm install -D portless

运行:

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

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

端口是怎么分配的

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

麻烦的是忽略 PORT 的框架:Vite、VitePlus、Astro、React Router、Angular、Expo、React Native。portless 对这类框架直接注入对应的 --port 标志,需要时加上 --host。注入能穿透 package script,只要命令以框架名或已知 runner 开头("dev": "vite""dev": "bunx vite" 都行)。

这部分我认为是整个项目里工程量最大、也最容易出错的地方。看它怎么划定边界。

注入的边界:克制是关键

自动改写用户命令是危险操作,portless 的处理相当细:

只动服务器命令。 devservepreviewstart、裸的 vitevite [root] 会拿到端口参数。vite buildvite optimizevp testastro 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 行为

代理重启或机器重启后,portless 复用最近一次运行的配置(端口、TLS、TLD),不会静默回退默认值。显式环境变量(PORTLESS_PORTPORTLESS_HTTPS 等)优先级永远最高。

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

状态存在 ~/.portless。代理在 sudo 下运行时,这个路径会从发起用户的 home 解析,保证代理和普通权限的应用进程共享同一套路由注册。

“For humans and agents”

README 副标题里有 “agents”。端口号对 AI 编程代理是个真实的痛点:端口变了、被占了、和测试脚本对不上,代理就得去猜。稳定可预测的 myapp.localhost 让代理验证开发服务器、在多项目间切换时不需要任何猜测。如果你在重度使用 AI 结对编程,这是它的直接价值。

需要知道的坑

  • pre-1.0。按项目安装时,不同贡献者可能跑不同版本;状态目录格式可能在版本间变化,届时需要重新执行 portless trust。团队统一全局安装可以减少摩擦。
  • 443 端口 + 本地 CA。首次运行会 sudo 提权并在系统里信任一个本地 CA。本地开发工具的常见做法,但对环境改动敏感的话要有心理准备。
  • 复杂脚本不享受自动注入。复合命令、env 前缀这类脚本,端口要自己在脚本里写。

我认为它适合三类人:本地同时跑多个前端项目的人、需要本地 HTTPS 测 secure cookie / Service Worker 的人、以及用 AI 代理写代码的人。解决的问题很具体,边界处理认真,值得一试。

这篇文章对你有帮助吗?

发表回复