返回探索
资讯VibeFix 编辑部更新于 2026年10月31日

Vercel 新项目默认跑 Node.js 26:LTS 扶正,fetch 默认走 HTTP/2

Vercel 2026 年 10 月 29 日宣布 Node.js 26 LTS 全面可用,成为新项目默认运行时。真正需要注意的不是新功能,而是默认规则:engines 写成 >=20 的老项目下次部署就会被带上 26,而 fetch 走 HTTP/2 后 statusText 会变空。

一名开发者在办公室桌前用笔记本电脑和显示器写代码

一名开发者在办公室桌前用笔记本电脑和显示器写代码

2026 年 10 月 29 日,Vercel 宣布 Node.js 26 LTS 在平台上全面可用,并且成为所有新项目的默认运行时。这条消息看起来平平无奇:又一个大版本扶正,又一次默认升级。但它真正值得注意的地方不在新功能,而在“默认”这两个字。新项目从此默认跑 Node.js 26,而一部分老项目在下一次部署时会被悄悄带上 26,开发者可能根本没有意识到自己已经升级了。

这就是为什么这篇新闻值得单独写一写。它不是一次需要你连夜跟进的大改版,而是一次需要你在下一次部署之前先看一眼配置的小变化。看一眼,花不了五分钟;不看,可能会在上线之后才发现某个依赖行为变了,或者某段读取响应信息的代码突然拿不到值了。下面把这次变化拆开讲清楚:到底改了什么、哪一部分真的会影响现有项目、以及部署之前应该检查哪几项。

这次到底改了什么

根据 Vercel 的更新日志,Node.js 26 LTS 现在同时覆盖构建和 Vercel Functions 两种场景。也就是说,不管是构建阶段跑的 Node,还是线上函数实际运行的 Node,都可以是 26。对于新项目,26 就是默认值,不需要额外配置。对于已经在跑的老项目,规则分两种情况,后面会细说。

随 26 一起来的有三样东西。第一,内置 fetch 默认走 HTTP/2,底层是 Undici 8。当目标服务器支持 HTTP/2 时,多个请求可以共享同一条连接,Vercel 的说法是,这能降低函数调用外部接口或数据库时的延迟。第二,Temporal API,一个用来替代 Date 的新日期时间接口,它的值不可变,并且自带时区和日历支持。第三,JavaScript 引擎升级到 V8 14.6,带来了一些新的语言特性,比如 Map.prototype.getOrInsert(),可以在键不存在时取默认值或插入默认值,省掉先判断再写入的样板代码。

另外还有一条容易被忽略的规则:Node.js 26 的小版本和补丁更新会在构建和函数上自动 rollout。也就是说,你锁定的是 26 这条大版本线,具体跑的是 26.x 里最新的小版本,这一点由平台负责往前推,不需要你每次手动跟进。这对安全补丁是好事,但也意味着“26”不是一个静止不变的目标,你的测试环境和线上环境都应该按“26 这条线”来理解,而不是某一个精确的小版本号。

真正会咬人的地方:宽松的 engines 范围

这次变化里最有实际杀伤力的一条,藏在 Vercel 更新日志的“自动升级”说明里:如果现有项目的 package.json 中 engines.node 字段允许 26,比如写的是 >=20,那么下一次部署时构建就会直接用上 Node.js 26。注意措辞:不是“建议你升级”,不是“下个版本再升级”,而是下一次部署就用 26。

很多项目写 engines 字段时都写得很宽松。写 >=20 的本意往往是“别低于 20 就行”,而不是“我已经准备好跑 26 了”。但在 Vercel 的规则下,这句话现在就等于“26 也可以”。项目本身可能完全没有为 26 做过测试,依赖里也可能有某个包在新版本下行为不同,结果就是一次例行部署顺带完成了一次大版本升级,而开发者事后才从构建日志里发现运行时变了。

这不是 Vercel 做错了什么。engines 字段本来就是用来声明兼容范围的,写得宽就意味着接受范围内的版本。但现实是,大量项目里的 engines 字段是很久以前随手写的,之后再也没有人回头看过它。这次默认切换正好把这笔旧账翻了出来:你的 engines 字段到底是在表达一个经过验证的兼容范围,还是只是一句很久没人维护的宽泛声明?如果是后者,现在就是收紧它的好时机。

手动升级的路径倒是很直接:把 engines.node 改成 26.x,然后重新部署。Vercel 也提醒了一点:用预构建方式部署 Node.js 26 函数的话,Vercel CLI 需要 65.8.0 或更高版本。这一点很容易在本地开发机上踩坑——项目代码改对了,部署工具却还是旧版本,结果部署行为和预期对不上。升级之前先看一眼 CLI 版本,比事后排查要省事得多。

{
  "engines": {
    "node": "26.x"
  }
}

我的判断是:不要把这次升级当成“平台自动帮你做了”的事,也不要把它当成“必须立刻跟进”的事。正确姿势是主动做一次选择:要么明确写 26.x 并跑一遍测试再部署,要么有意识地把范围收紧到你已经验证过的版本,比如 24.x,等有空再单独安排升级。最糟糕的选择是第三种——什么都不做,让下一次例行部署替你做决定。

fetch 默认走 HTTP/2:唯一需要改代码的地方

如果说 engines 范围是“配置上需要注意”,那么 fetch 的变化就是“代码上可能需要改”。Vercel 明确说,内置 fetch 现在默认走 HTTP/2。多个请求共享连接、延迟可能降低,这些都是好处。但 HTTP/2 有一个和 HTTP/1.1 不同的行为:响应里没有 reason phrase,也就是状态文本。

具体来说,在 HTTP/1.1 下,响应带有一句状态文本,比如 200 对应 OK、404 对应 Not Found,代码里读 response.statusText 就能拿到这句话。但在 HTTP/2 下,这句话不存在,statusText 会是空字符串。如果你的代码里有用 statusText 来做日志、做错误提示、或者做分支判断,切换到 HTTP/2 之后这些逻辑就会悄悄失效——不是报错,而是拿到空字符串之后继续往下走,这是最难排查的一类问题。

修法并不复杂:改用 response.status,也就是数字状态码,来做判断和记录。数字状态码在两个协议下都稳定存在,不依赖状态文本。Vercel 的文档里也给出了同样的建议。与其等上线后发现日志里状态文本全空了再回头找,不如现在就全局搜一遍:

grep -rn "statusText" --include="*.ts" --include="*.js" .

如果搜出来是零结果,恭喜,这一部分对你没有影响。如果搜出来有结果,逐个看一下:是只用来打日志,还是真的参与了业务判断。只打日志的,换成 status 或者干脆去掉;参与判断的,必须改成 status,否则就是埋了一个只在 HTTP/2 下才会触发的 bug。

当然,Vercel 也留了退路:如果你暂时不想让函数里的 fetch 走 HTTP/2,可以把环境变量 VERCEL_FETCH_DISABLE_H2 设为 1,然后重新部署,就能回到 HTTP/1.1。需要注意两点:第一,这个变量只影响函数里的 fetch,不影响构建阶段的 fetch;第二,它应该是过渡方案,不是长期方案。HTTP/2 是大方向,长期靠一个禁用开关过日子,等于主动放弃连接复用带来的延迟收益,而且以后一旦这个开关的行为有变,你又要再处理一次。更合理的做法是:先修 statusText,确认没问题后再放开 HTTP/2;只有在修起来确实有困难、或者某个上游服务在 HTTP/2 下有明确问题时,才临时用这个开关顶一下。

还有一个细节值得提:如果你自己设置了全局 dispatcher,或者给某次 fetch 单独传了 dispatcher,那么你自己的配置优先于默认行为。也就是说,自定义网络层的项目受这次默认切换的影响会小一些,但也不能完全置身事外——至少要确认你的 dispatcher 在 Node.js 26 和 Undici 8 下仍然工作正常。

Temporal:真正的长期收益,但别急着重写

三项新东西里,从长期看最有价值的是 Temporal。任何写过 JavaScript 日期处理的人都知道 Date 有多难用:月份从 0 开始算、时区处理靠手工、夏令时切换容易出边界问题、Date 对象本身还可变,一个不小心就在别处被改掉了。Temporal 的设计就是冲着这些痛点来的:值不可变,时区和日历是内置概念,日期运算有专门的接口。

但“长期有价值”不等于“现在就全量重写”。Date 代码遍布老项目,日期逻辑又是最容易在边界条件上出错的地方——跨时区、跨夏令时切换、月底月初、闰年,这些场景每一个都可能藏一个只有特定日期才会触发的 bug。把全站的 Date 一次性换成 Temporal,等于在没有明确收益的情况下主动引入一波回归风险。

更稳妥的节奏是:新写的日期逻辑优先用 Temporal,特别是涉及多时区展示、跨时区换算、日程计算的新功能;老代码保持不动,只在确实要改某块日期逻辑的时候,顺带把那一小块换成 Temporal。这样既能逐步积累 Temporal 的使用经验,又不会为了一次运行时升级而把整个日期层翻一遍。等团队对 Temporal 的接口足够熟悉、测试覆盖也跟上之后,再考虑更大范围的迁移。

同理,V8 14.6 带来的 Map.prototype.getOrInsert() 这类新特性,也适合“新代码顺手用、老代码不动”的策略。知道有这个方法就够了,遇到需要“有则取、无则插”的场景时用它写得更干净;没必要为了用新特性而把现有的 Map 操作全部重写一遍。

部署之前,先过一遍这份清单

把上面的分析收敛成一份可以直接照着做的清单。下一次部署之前,花几分钟逐项确认:

第一,打开 package.json,看 engines.node 写的是什么。如果是 >=20 或者其他宽松范围,先想清楚:你是想这次就上 26,还是想先留在 24.x。想上 26,就明确写 26.x;想留,就把范围收紧到你验证过的版本。不要让宽松范围替你做决定。

第二,全局搜 statusText,确认所有读取状态文本的地方都已经改成 status,或者确认搜出来是零结果。这是这次变化里唯一可能需要改代码的点,值得单独确认一次。

第三,检查所有通过 fetch 调用的外部接口和数据库:这些调用在 HTTP/2 下是否正常。重点看那些对响应细节有依赖的调用,比如依赖特定响应头、依赖连接行为的逻辑。可以在预发布环境先部署一次,跑一遍关键链路,再推到生产。

第四,如果你用预构建方式部署,确认本地 Vercel CLI 是 65.8.0 或更高版本。版本号不对,部署行为可能和预期不一致,排查起来会浪费不少时间。

第五,确认构建和函数的小版本策略:你锁定的是 26 这条线,小版本和补丁由平台自动推。这意味着本地开发环境的 Node 版本最好也跟到 26,避免“本地是 24、线上是 26”这种环境不一致带来的调试成本。用版本管理工具把本地 Node 切到 26,再跑一遍测试套件,是成本最低的验证方式。

第六,如果你的项目确实有理由暂时留在 HTTP/1.1,把 VERCEL_FETCH_DISABLE_H2 设为 1 并重新部署,同时把“为什么需要这个开关、什么时候可以去掉”记下来。没有记录的临时开关,过三个月就会变成没人敢动的永久配置。

Node 20 的背景:这条线正在收尾

还有一个背景值得交代,但要说得谨慎一些。根据第三方媒体 Firerun 对 Vercel 文档的梳理,Vercel 的版本页面现在列出 26.x 为默认,24.x 和 22.x 仍可选用,而 20 已经不在列表中。Firerun 同时提到,Vercel 曾在 7 月 14 日的更新日志中表示,将在 10 月 1 日停用 Node.js 20,背景是该版本已在 4 月 30 日结束生命周期。这里要说明白:关于 20 已从列表中消失的说法,来自 Firerun 对文档的解读,而非 Vercel 这篇 26 LTS 更新日志本身的原文,引用时应当保留这个限定。

即便加上这个限定,方向也是清楚的:20 这条线已经走完它的生命周期,24 和 22 还在,但 26 已经是默认。对于还在 20 上的项目,这次变化其实是一个提醒:停留在已结束生命周期的版本上,意味着不再有安全补丁,越往后拖,升级跨度越大、风险越高。从 20 直接跳到 26,比从 24 升到 26 需要验证的东西更多,所以还在 20 上的项目更应该单独安排一次升级计划,而不是等某次部署被默认规则推着走。

对不同团队意味着什么

同一个默认切换,落在不同团队头上的分量是不一样的。个人项目和小团队最容易中招,因为这类项目的 package.json 往往是很久以前脚手架生成的,engines 字段写完就没再动过,测试覆盖也不一定完整。对这类项目来说,最划算的做法不是研究 26 的每一个新特性,而是先把上面那份清单走一遍:收紧 engines、搜 statusText、本地切到 26 跑一遍测试。这三件事做完,升级的风险就已经去掉了一大半,剩下的新特性可以慢慢用。

中等规模的团队则要多想一层:有多少个服务、多少个仓库共用同一套部署配置。如果 engines 范围是写在共享模板里的,一处宽松就意味着所有用这个模板的项目都会在下一次部署时被带上 26。这时候正确的做法是先改模板、再逐个服务验证,而不是让每个服务在各自的部署时间点上陆续“被升级”,那样问题会分散在几天甚至几周里冒出来,排查时很难把它们联系到同一次默认切换上。统一时间窗口、统一验证,出了问题也更容易定位。

还有一类项目需要格外小心:依赖了很久没人维护的老包,或者自己魔改过网络层的项目。Node 大版本升级最常见的翻车点从来不是语言语法,而是某个依赖在新版本下悄悄变了行为,或者某个被反复打补丁的网络层在新版 Undici 下不工作了。这类项目的升级策略应该是“先在预发布环境完整跑一遍,包括那些平时不常走的链路”,而不是“先上生产,出问题再回滚”。回滚当然是可行的,但回滚本身也是一次部署,同样会消耗时间和注意力,能提前验证就不要事后补救。

反过来说,也有一种过度反应需要避免:因为怕升级而把 engines 钉死在旧版本上不动。钉死在 24.x 短期内是安全的,但 24 也终究会走到生命周期尽头,到时候要跨的版本差只会更大。健康的节奏是“每个大版本都主动安排一次升级”,而不是“能拖多久拖多久”。这次 26 的切换,其实就是一次成本很低的练兵机会:变化点清晰、回退手段明确、正好可以用来把团队的升级流程跑顺一遍。

结论:小变化,大提醒

回过头看,Node.js 26 LTS 登陆 Vercel 本身不是什么戏剧性事件。没有颠覆性的新功能,没有必须连夜迁移的破坏性变更,甚至大部分项目在升级之后都不会感觉到任何不同。它的意义在于提醒了两件事:第一,平台默认值会变,而且会通过你很久没看过的 engines 字段悄悄影响你;第二,HTTP/2 这种底层协议的变化,表面上对开发者透明,实际上会在 statusText 这种细节上露出差别。

对个人开发者和小团队来说,最好的应对就是上面那份清单:收紧 engines、搜一遍 statusText、预发布环境跑一遍关键链路、确认 CLI 版本。做完这几项,这次升级就是一次平顺的例行升级。反过来,如果什么都不做,等下一次部署自动把你带上 26,再回头排查问题,成本只会更高。默认值变了不可怕,可怕的是你不知道默认值变了。

阅读 0评论 0

评论 (0)

ME
0/1000
评论加载中...

原始来源

浏览项目广场发布你的项目

相关文章

昏暗办公室里,一名开发者背对镜头,面对多块显示代码的屏幕
资讯
不用每步都点头,也别直接放行:Copilot 辅助审批全面可用

GitHub 2026 年 10 月 26 日宣布 Copilot 辅助审批全面可用:模型先筛一遍命令、路径和网址请求,明显安全的自动放行,其他的仍然问你。省的是提示,不是监督——模型会犯错,这不是沙箱的替代品。

开发工作流AI 编程实践安全与隐私
一名开发者在办公桌前看着显示代码的大屏幕,桌上还有笔记本电脑
资讯
不是新模型,是一本新规则书:OpenAI 把 Model Spec 重组成五个价值

2026 年 10 月 29 日,OpenAI 更新了 Model Spec:没有新模型、没有新基准、没有调价,只有五个价值——忠实于人类意图、最小化伤害、诚实与透明、促进人类能动性、用心——以及一句坦白:现在的模型还没有完全做到这一点。

产品发布AI 编程实践