前端前線 2026 年 7 月 27 日

2026-07-27 — Vue 3.6 RC.2 收斂 Vapor Mode 行為、Svelte 5.56.8 修補錯誤邊界與 select hydration

primary=https://github.com/vuejs/core/releases/tag/v3.6.0-rc.2 primary=https://github.com/sveltejs/svelte/releases/tag/svelte%405.56.8 primary=https://github.com/sveltejs/svelte/pull/18556 primary=https://github.com/sveltejs/svelte/pull/18561

Vue 3.6 RC.2:Vapor Mode 事件委派改為預設關閉,補齊十餘個 hydration 與 suspense 邊界問題

Vue.js GitHub Releases · 2026-07-22

背景

Vue 核心團隊於 2026 年 7 月 22 日發布 v3.6.0-rc.2,是 Vue 3.6 進入 RC 階段後的第二個候選版本。Vue 3.6 的兩大主軸是 Vapor Mode 與 alien-signals 響應式重寫,rc.1 已宣告 Vapor Mode 功能集完成,rc.2 則專注在穩定性修補與一項行為調整。Vapor Mode 是一種新的 SFC 編譯模式,透過 <script setup vapor><template vapor> 逐元件選擇加入,編譯期直接產生 DOM 操作程式碼,不經過 VNode 與 diff,因此可大幅縮減基礎打包體積;官方引用 js-framework-benchmark 的第三方測試,稱其效能已追上 Solid 與 Svelte 5。

另一項背景是 @vue/reactivity 的全面重寫,改採 alien-signals 的 push-pull 演算法:訊號變更時只做一次廉價的「dirty 旗標」向下傳播,實際重新計算則延後到 computed 被讀取的當下才觸發,且核心刻意不使用 Array/Set/Map、也禁止遞迴呼叫,以換取更低的記憶體開銷。這使得 rc.1 的響應式效能號稱達到 Vue 3.4 的四倍左右,而 rc.2 是在這個新地基上繼續打磨 Vapor 執行期的邊界情況。

核心改動

rc.2 最主要的行為變更是一項標記為 BREAKING CHANGES 的調整:Vapor Mode 的事件委派(event delegation)從預設開啟改為顯式選擇加入(#15127)。此前 Vapor 會自動把支援的事件委派到 document 節點以換取效能,但這與 VDOM Mode 的原生事件行為不一致——例如祖先節點呼叫 stopPropagation() 時,VDOM Mode 下子元件的處理器仍可能被跳過,兩種模式表現不同步。修改後,DOM 事件監聽器預設直接掛在元素本身,若要恢復委派最佳化,需明確加上 Vapor 專屬的 .delegate修飾符:

<!-- 舊:預設委派到 document -->
<button @click="onClick" />

<!-- 新:需顯式加上 .delegate 才會委派 -->
<button @click.delegate="onClick" />

同時,compilerOptions.eventDelegation 選項已被移除,既有專案若曾設定此選項需直接刪除,改為在個別高頻事件監聽器上加 .delegate。除此之外,本版還修了十餘個 Vapor 執行期的邊界 bug,涵蓋 hydration、transition 與 suspense 之間的互動:

  • compiler-vapor:修正 helper 與快取變數命名衝突(#15124
  • runtime-core/runtime-vaporsetCurrentInstance 呼叫後正確還原為 undefined effect scope(#15141
  • runtime-vapor:transition hook 需在 suspense 插入之前套用(#15133);生產環境下 setup 錯誤需被正確攔截(#15130
  • runtime-vapor:hydrate 未包裝的 interop slot 內容時建立 slot anchor(#15131);deferred vdom hydration 下透過 interop hydrate vapor 元件(#15132
  • runtime-vapor:mount hook 延後到擁有該元件的 suspense boundary(#15139);post-render effect 延後到 vdom suspense boundary(#15144
  • runtime-vapor:保留 pending 中的非同步元件位置(#15147);非同步 setup 結果處理時還原 instance context(#15129);interop 更新時同步 transition hook(#15140
  • runtime-vapor:hydration mutation 後更新邏輯子節點快取(#15145);vdom interop 下驗證 props(#15111

影響範圍

由於 Vapor Mode 完全是逐元件選擇加入(opt-in),這批變更目前只影響已在 3.6 beta/RC 中嘗試 vapor 標記的專案,不會波及仍使用傳統 VDOM Mode 的既有應用。事件委派語意調整是本版唯一的破壞性變更,遷移步驟明確:移除 compilerOptions.eventDelegation 設定,並在需要委派最佳化的高頻靜態事件監聽器上補上 .delegate。剩餘的十餘項修補集中在 hydration 與 suspense/transition 交界處,多數是 Vapor 與 VDOM interop 情境下才會觸發的邊界案例,對純 Vapor 或純 VDOM 應用影響有限;官方建議現階段僅在效能敏感頁面局部採用 Vapor,或用於全新的小型應用。

原始來源:Vue.js v3.6.0-rc.2 GitHub Releaseminor 分支 CHANGELOG.md


Svelte 5.56.8:修掉錯誤邊界卡死與 select 選取遺失兩個 hydration 陷阱

Svelte GitHub Releases · 2026-07-24

核心改動

Svelte 團隊於 2026 年 7 月 24 日發布 patch 版本 5.56.8(commit 44a7813),修正兩個獨立的 hydration 缺陷。第一個問題出在 <svelte:boundary> 的錯誤處理機制:boundary 元件透過 onerrorfailed snippet 提供的 reset 函式讓使用者從錯誤狀態恢復,此行為隨 #17672 引入,官方文件寫明 onerror「會在 hydration 時以反序列化後的錯誤物件被呼叫」。但實際上,若 boundary 在 SSR 階段就已經失敗,hydration 時會走 #hydrate_failed_content 這條路徑,該路徑從未呼叫 onerror,且傳給 failed snippet 的 reset 是無效的空函式,導致一旦以失敗狀態完成 hydration,boundary 就再也無法離開這個狀態。

下游最直接受影響的是 SvelteKit:+error.svelte 正是靠這套機制運作,這個缺陷使得使用者從一個伺服端渲染的錯誤頁面導航離開後,該錯誤頁仍卡在畫面上不會被卸載(對應 sveltejs/kit#16345)。修補方式(#18556)是把原本內嵌在 #handle_error 裡的 reset/onerror 邏輯抽成獨立的 #create_reset,讓 hydration 路徑也能共用;由於 hydration 期間不允許直接修改狀態,onerror 改為在 microtask 中呼叫,與既有的非同步錯誤路徑保持時序一致。

影響範圍

第二個修補(#18561)處理的是 <select> 元素搭配 spread attributes 時遺失選取狀態的問題。當 <select {...props}> 這類寫法從未透過 spread 提供 value 時,元件仍會初始化選項變動的 mutation observer;該 observer 過去把「內部 __value 不存在」誤判為「明確設為 undefined,結果只要動態新增或移除一個 <option>,就會把使用者原本的選取清空。修補後,只有在 __value確實存在時才會重新套用程式化選取,未提供 value 的 spread 用法會保留瀏覽器原生的選取狀態,同時不影響原本透過 bind:value 或顯式 undefined 的既有行為。這兩項修補都屬於 patch 等級,不涉及 API 變動,直接受影響的是使用 <svelte:boundary>/SvelteKit 錯誤頁面的專案,以及以 spread 方式驅動 <select> 選項清單的元件作者。

原始來源:Svelte 5.56.8 GitHub ReleasePR #18556PR #18561

End of article
0
Would love your thoughts, please comment.x
()
x