编程 补丁版本也会改行为:Vue 3.5.44 中四处影响运行时的修复

2026-10-20 21:07:22

补丁版本也会改行为:Vue 3.5.44 中四处影响运行时的修复

Vue 3.5.44 在 2026-10-13 发布,包含 25 个以上的修复,涉及 reactivity、Suspense、Teleport 和 SSR。补丁版本号很容易让人跳过更新日志,但这一批里有四条改动的是运行时行为,并非只做缺陷收尾。已经在 3.5 上的项目升级成本不高,但下面四类代码值得先扫一遍。

信源:Dev News 2026-10-14 的摘要,以及 vuejs/core 的 releases 页(2026-10-13,v3.5.44)。

1. watcher 在另一个 effect 内运行时不收集依赖(issue #5009)

Vue 的 effect 用 activeEffect 栈管理依赖收集。当 watch 的 getter 在另一个 effect(比如 watchEffect 的回调或 computed 的求值过程)里被执行时,getter 内部读取的响应式数据会被记录到外层 effect 的依赖集合里,而不是只属于这个 watcher。后果有两个方向:外层 effect 被 watcher 的依赖带着重跑;或者预期该被 watcher 追踪的依赖,实际上挂到了别人身上。

最小复现(示意):

import { ref, watch, watchEffect } from 'vue'

const flag = ref(true)
const count = ref(0)
let runs = 0

// watcher 在外层 effect 内创建,getter 在外层 activeEffect 上下文中求值
watchEffect(() => {
flag.value
watch(count, () => { runs++ })
})

count.value++ // 3.5.44 之前:外层 effect 被 count 拖着重跑,watcher 被重新创建

修复后,watcher 的依赖跟踪与它所在的 effect 隔离,count 的变化不再触发外层 effect。受影响的是依赖旧行为建立依赖的代码——比如「外层副作用顺带把内层 watcher 拉起来」这种写法,升级后 watcher 可能不再按预期触发;如果外层 effect 反复重跑,旧 watcher 也不会因为外层重跑而被回收。

2. once watcher 回调抛错后停止

{ once: true } 的清理逻辑挂在回调正常返回之后。回调抛错时清理被跳过,watcher 仍处于活跃状态,源的后续变化会再次进入同一个回调。

import { ref, watch } from 'vue'

const source = ref(0)

watch(source, () => {
throw new Error('boom')
}, { once: true })

source.value++ // 之前可能被重复调度;3.5.44 之后抛错也会停止

现在抛错同样会停掉 watcher,不再重复尝试。如果一次性 watcher 里包着可能失败的请求或解析逻辑,失败后不会再有第二次机会,重试需要自己显式处理。

3. SSR 传播 async setup 的错误

之前的服务端渲染里,async setup 里 reject 的 Promise 可能被吞掉,最终返回一份空掉或只渲染了一半的 HTML,HTTP 状态却是 200。

// App.vue
export default {
async setup() {
const res = await fetch('/api/data')
return { data: await res.json() } // 这里 reject
}
}

3.5.44 之后错误会向外传播:要么交给 app.config.errorHandler 或组件上的 onErrorCaptured,要么直接抛出。SSR 侧需要确认有兜底,否则同一个故障会从「静默返回不完整页面」变成「500」。

const app = createSSRApp(App)
app.config.errorHandler = (err) => {
// 记录并转成明确的错误响应
}

4. v-html 正确序列化 0 和 false


import { ref } from 'vue'
const value = ref(0)

绑定的值是 0 或 false 时,此前可能被当成空值渲染成空字符串。修复后按字符串序列化,输出 0、false。这类绑定通常出现在计数、开关状态直出 HTML 的位置,升级前后的渲染结果会肉眼可见地不同。

升级检查清单

  • 搜索写在 computed getter、watchEffect 回调、render 函数里的 watch / watchEffect,确认它们不依赖外层 effect 的上下文
  • 检查「副作用外层触发内层 watcher」的写法,看升级后 watcher 是否还按原路径触发
  • 检查 once: true 的 watcher 内是否有会抛错的逻辑,失败后是否需要显式重试
  • SSR 项目确认 async setup 的 catch、onErrorCaptured、app.config.errorHandler 都在位
  • 检查 v-html 绑定的值可能为 0 / false 的地方,对比升级前后的输出
  • 用 pnpm/npm 锁定版本,补丁版本也固定下来,CI 里把关键交互跑一遍
复制全文 生成海报 Vue 前端 响应式 SSR

推荐文章

程序员茄子在线接单