預計2019年釋出的Vue3.0到底有什麼不一樣的地方?

Fundebug發表於2019-01-16

摘要: Vue 3.0預覽。

Fundebug經授權轉載,版權歸原作者所有。

還有幾個月距離 vue2 的首次釋出就滿 3 年了,而 vue 的作者尤雨溪也在去年年末釋出了關於 vue3.0 的計劃,如果不出意外,我們將在今年的某個時間點見證 Vue3.0 的釋出,雖然前幾天在《StateOfJS: 2018 年 JavaScript 生態圈趨勢報告》一文中我們看到目前 Vue 的使用者比 React 還少了不少,但在 Github 上 Vue 的 star 數已經超越 React,可見使用者對 Vue 的喜愛,那即將釋出的 Vue3 又有什麼新特性呢?我們一起來看看吧!

Vue 3.0 已經在原型設計階段了,而且我們已經實現了一個與 2.0 的特性近乎相等的執行時了。下文中列出的許多條目,要麼已經實現了,要麼已經確認可實現。那些還未實現或者仍在探索階段的條目會用一個“*”標記

預計2019年釋出的Vue3.0到底有什麼不一樣的地方?

效能提升

一句話簡介:更小巧,更快速;支援搖樹優化;支援 Fragments 和跨元件渲染;支援自定義渲染器。

  • 更小巧:這份新的程式碼庫在設計之初就考慮到了對“搖樹優化 (tree-shaking)”的友好。那些如內建元件 (、) 、執行時工具性指令(v-model)等特性將變為按需匯入,所以也是“可搖樹的”。對於這個新的執行時,它的大小將永遠保持在 10kb 之下。另外,使這些特性變為“可搖樹的”後,我們就可以提供更多的內建特性,同時還不會增加網路負載——如果沒使用到這些特性的話。

搖樹優化,是一種在打包時去除沒用到的程式碼的優化手段,谷歌有一篇教程可以瞭解下: Reduce JavaScript Payloads with Tree Shaking

預計2019年釋出的Vue3.0到底有什麼不一樣的地方?

  • 更快:在前期的基準測試中,我們看到整體效能有了一倍的提升,包括虛擬 DOM 的掛載和打補丁(patching,指更新——譯註) 的速度(我們從 Inferno 那裡學了好些個技巧過來——Inferno 是目前速度最快的虛擬 DOM 實現),以及元件例項化速度和資料監測的效能。在 3.0 中,你應用的啟動時間將縮減一半。
  • 支援 Fragments 和 Portal:雖然體積更小了,但 3.0 還將內建對 Fragments (即允許元件擁有多個根節點) 和 Portal (即允許在 DOM 的其他位置進行渲染,而不是元件內部) 的支援。

關於 Portal ,你可以將其理解為跨元件渲染或者異地渲染,vue-portal 是一個第三方實現,可以瞭解一下;Fragments 特性也有一個第三方庫,但譯者認為這個庫的內部實現不夠完善,叫做 vue-fragments,感興趣可以瞭解一下。

  • 增強的 slot 機制:所有由編譯器生成的 slot 都將是函式形式,並且在子元件的 render 函式被呼叫過程中才被呼叫 (譯註:現在只有 scoped slot 才是函式形式,其渲染的時機也是在父元件的渲染進行時)。這使得 slot 中的依賴項 (即資料——譯註) 將被作為子元件的依賴項,而不是現在的父元件;從而意味著:1)當 slot 的內容發生變動時,只有子元件會被重新渲染;2)當父元件重新渲染時,如果子元件的內容未發生變動,子元件就沒必要重新渲染。這種機制的改變,可以提供更精確的變動探測,也就可以消除沒必要的重渲染。
  • 支援自定義渲染器 (Renderer):這個 API 可以用來建立自定義的渲染器,它將作為“一等公民”出現,到時不再需要 fork 一份 Vue 的程式碼來通過修改實現自定義。這個 API 的到來,將使得那些如 Weex 和 NativeScript 的“渲染為原生應用”的專案保持與 Vue 的同步更新變得更加容易。除此之外,還將使得那些為了各種用途而建立自定義渲染器變得極其容易。

編譯器相關的提升

  • 如果採用的是支援“搖樹優化”的打包器,模板中使用到的那些可選特性,在生成的程式碼中將通過 ES 的模組語法匯入;而在打包後的檔案中,那些沒用到的可選特性就會被“搖掉”。
  • 由於新的虛擬 DOM 實現所帶來的提升,我們可以執行一些更加高效的編譯耗時優化,如靜態樹提升(static tree hoisting)、靜態屬性提升(static props hoisting);以及為執行時提供一些來自編譯器的提示,以此避開子元件的規範過程 (children normalization);提供 VNode 快速建立路徑; 等等。
  • 我們計劃對解析器進行重寫,以便在對模板進行編譯發生錯誤時,可以提供錯誤發生的位置資訊;除此之外還可以帶來對模板的 source map 支援;還可以支援第三方工具如 eslint-plugin-vue 和 IDE 的語言服務 (language services) 特性。

API 變動

一句話介紹:除渲染函式 API 和 scoped-slot 語法之外,其餘均保持不變或者將通過另外構建一個相容包來相容 2.x。

  • 模板語法的 99% 將保持不變。除了 scoped slot 語法可能會有一些微調之外,我們還沒有任何其他針對模板的變動計劃。
  • 3.0 版本將原生地支援基於 class 的元件,而且無需藉助任何編譯及各種 stage 階段的特性,以此提供良好的編寫體驗。許多現有的 (元件) 配置項將有對應的合理的 class 版本的 API。各種 stage 階段的特性,如 class 的靜態欄位和裝飾器 (decorator) 等仍然可以選擇性地使用,以此增強編寫體驗。另外,整體的 API 在設計時也將考慮 TypeScript 的型別推斷特性。3.x 的程式碼庫本身將用 TypeScript 來編寫,並提供增強的 TypeScript 支援。(就是說,TypeScript 的使用與否仍然是整體可選的)
  • 2.x 系列的基於物件的元件格式仍將受支援,不過會在內部將其轉換為一個相應的 class。
  • 仍然支援 Mixins。*
  • 為了避免在安裝外掛時造成對 Vue 的執行時的修改,頂層 API 可能會做一個大的翻修。到時,外掛的作用域將只侷限到具體的一個元件樹,使得對那些依賴於某些具體外掛的元件的測試變得容易,也會使得在同一個頁面中掛載多個使用不同外掛——但使用同一個 Vue 執行時——的 Vue 應用變為可能。*
  • 函式式元件將支援純函式的書寫形式——不過,這樣的話非同步元件就需要通過一個輔助性函式來顯式地建立了。
  • 變動最大的部分將是渲染函式 (render) 中的虛擬 DOM 的格式。我們現在正在收集主流的第三方庫的作者們的反饋,在對這些變動有了更多的信心之後,我們還會將更多的細節曝光;雖然變動較大,但是隻要你沒在你的應用中重度使用手寫的渲染函式 (不是指 JSX),那麼變動之後的升級應該會比較容易。

程式碼重構

一句話介紹:更優良的內部模組解耦;TypeScript;更易於貢獻的程式碼庫。

在從零開始編寫 3.0 之初,“達到更加清晰和更易維護的架構,特別是為了讓程式碼的貢獻變得容易”就是我們的目標。為了對複雜性進行隔離,我們將一些內部功能拆分為了多個單獨的包。例如,observer 模組將成為一個單獨的包,擁有自己對外的 API 和自己的測試用例;不過請注意,這不會對框架級的 API 造成影響——你不需要另外手動從多個包裡匯入許多小件小件的模組就可以使用 Vue,相反 Vue 的最終包會事先裝配好這些內部包。

另外,程式碼庫現在改為了用 TypeScript 編寫;雖然這會使得“熟練 TypeScript”成為對新程式碼庫進行貢獻的一個前置要求,不過我們相信有型別資訊配合 IDE 的支援,對於一個新的貢獻者來說,要做出有意義的貢獻,實際上反而會更加容易。

將 observer 和 scheduler 解耦為分開的兩個包後,我們還可以拿一些替代的實現對這兩個包進行置換試驗。例如,我們可以實現一個相容 IE11、API 也相同的 observer;或者實現另外一種利用 requestIdleCallback 來在長耗時的更新中產出工作成果到瀏覽器的 scheduler。

預計2019年釋出的Vue3.0到底有什麼不一樣的地方?

重寫虛擬 DOM (Virtual DOM Rewrite)

隨著虛擬 DOM 重寫,我們可以期待更多的 編譯時(compile-time)提示來減少 執行時(runtime)開銷。重寫將包括更有效的程式碼來建立虛擬節點。

預計2019年釋出的Vue3.0到底有什麼不一樣的地方?

優化插槽生成(Optimized Slots Generation)

在當前的 Vue 版本中,當父元件重新渲染時,其子元件也必須重新渲染(11 月 20 日更新:這句話是不嚴謹的,非常容易產生誤導,我覺得有必要說明一下: 2.0 元件的重新渲染就是元件粒度的,除非修改的資料是子元件的 props,才會觸發子元件的重新渲染。引用自:(juejin.im/pin/5bf28dd…)。 使用 Vue 3 ,可以單獨重新渲染父元件和子元件。

預計2019年釋出的Vue3.0到底有什麼不一樣的地方?

靜態樹提升(Static Tree Hoisting)

使用靜態樹提升,這意味著 Vue 3 的編譯器將能夠檢測到什麼是靜態元件,然後將其提升,從而降低了渲染成本。它將能夠跳過未整個樹結構打補丁的過程。

預計2019年釋出的Vue3.0到底有什麼不一樣的地方?

靜態屬性提升(Static Props Hoisting)

此外,我們可以期待靜態屬性提升,其中 Vue 3 將跳過不會改變節點的打補丁過程。

預計2019年釋出的Vue3.0到底有什麼不一樣的地方?

基於 Proxy 的觀察者機制

目前,Vue 的反應系統是使用 Object.defineProperty 的 getter 和 setter。 但是,Vue 3 將使用 ES2015 Proxy 作為其觀察者機制。 這消除了以前存在的警告,使速度加倍,並節省了一半的記憶體開銷。

為了繼續支援 IE11,Vue 3 將釋出一個支援舊觀察者機制和新 Proxy 版本的構建。

相容 IE 11

一句話介紹:IE 11 將受到支援,但將會是另外構建一個版本 (build) 的形式支援,不過這個版本會存在與 Vue 2.x 響應式機制所存在的同樣的侷限。

新的程式碼庫目前只針對主流瀏覽器,而且我們假定他們都支援 ES2015。但是,哎,我們也知道在可預見的未來還有很多使用者仍然需要支援 IE11。除了 Proxy 外,大多數 ES2015 的特性都可以用轉譯或者墊片的方式在 IE11 中使用。我們的計劃是另外單獨實現一個具有同樣 API 的替代性 observer,不過是基於老式的 Object.defineProperty API;然後再通過單獨構建一個使用這個實現的 Vue 3.x 版本 (build) 進行釋出,不過這個單獨的版本還是會有 Vue 2.x 在變動探測方面所存在的問題,所以它其實並不是一個完全相容 3.x 的一個版本。我們也意識到這會給第三方庫的作者們帶來某些不便,因為他們需要考慮兩個不同版本之間的相容性問題,不過當我們真的推進到那個階段時,那時我們肯定會確保提供一份清晰的指導。

監測機制

一句話介紹:更加全面、精準、高效;更具可除錯性的響應跟蹤;以及可用來建立響應式物件的 API。

3.0 將帶來一個基於 Proxy 的 observer 實現,它可以提供覆蓋語言 (JavaScript——譯註) 全範圍的響應式能力,消除了當前 Vue 2 系列中基於 Object.defineProperty 所存在的一些侷限,如:

  • 對屬性的新增、刪除動作的監測
  • 對陣列基於下標的修改、對於 .length 修改的監測
  • 對 Map、Set、WeakMap 和 WeakSet 的支援

另外這個新的 observer 還有以下特性:

  • 公開的用於建立 observable (即響應式物件——譯註) 的 API。這為小型到中型的應用提供了一種輕量級的、極其簡單的跨元件狀態管理解決方案。(譯註:在這之前我們可以通過另外 new Vue({data : {…}}) 來建立這裡所謂的 observable;另外,其實 vuex 內部也是用這種方式來實現的)
  • 預設為惰性監測(Lazy Observation)。在 2.x 版本中,任何響應式資料,不管它的大小如何,都會在啟動的時候被監測。如果你的資料量很大的話,在應用啟動的時候,這就可能造成可觀的效能消耗。而在 3.x 版本中,只有應用的初始可見部分所用到的資料會被監測,更不用說這種監測方案本身其實也是更加快的。
  • 更精準的變動通知。舉個例子:在 2.x 系列中,通過 Vue.set 強制新增一個新的屬性,將導致所有依賴於這個物件的 watch 函式都會被執行一次;而在 3.x 中,只有依賴於這個具體屬性的 watch 函式會被通知到。
  • 不可變監測物件(Immutable observable):我們可以建立一個物件的“不可變”版本,以此來阻止對他的修改——包括他的巢狀屬性,除非系統內部臨時解除了這個限制。這種機制可以用來凍結傳遞到元件屬性上的物件和處在 mutation 範圍外的 Vuex 狀態樹。
  • 更良好的可除錯能力:通過使用新增的 renderTracked 和 renderTriggered 鉤子,我們可以精確地追蹤到一個元件發生重渲染的觸發時機和完成時機,及其原因。

預計2019年釋出的Vue3.0到底有什麼不一樣的地方?

釋出時間

不必太過擔心,至少還能緩半年。

預計2019年釋出的Vue3.0到底有什麼不一樣的地方?

參考來源: Plans for the Next Iteration of Vue.js [譯] 尤雨溪:Vue 3.0 計劃

相關文章