「中文翻譯」Vue3的誕生之路

圖怪獸_238f42cf684d3a7e6aae1bd23dd19c33_76093.png
觀感度:🌟🌟🌟🌟🌟前端

口味:麻辣小龍蝦vue

烹飪時間:10mingit

本文已收錄在Github github.com/Geekhyt,感謝Star。

原文地址:https://increment.com/frontend/making-vue-3/github

譯者:童歐巴算法

因時間有限,文中翻譯不對的地方還請指出,望海涵。想感覺原汁原味還請移步上方連接。致敬尤大!後端

Vue3 的誕生之路

EVAN YOU數組

重寫 Vue.js 下一個主要版本的經驗瀏覽器

在過去的一年中,Vue 團隊一直在研究 Vue.js 的下一個主要版本,咱們但願在 2020 年上半年發佈該版本。(在撰寫本文時,這項工做仍在進行中。)Vue 的新的主要版本的構想造成於 2018 年年底,當時 Vue 2 的代碼庫已經兩年半大了。在通用軟件的生命週期中聽起來可能並不長,可是在此期間,前端環境發生了翻天覆地的變化。前端框架

有兩個主要的因素促使咱們開發(重寫) Vue 新的主要版本:首先是主流瀏覽器廣泛支持了新的 JavaScript 語言特性。其次,隨着時間的推移,當前代碼庫中的設計和架構問題已經暴露出來。架構

爲何要重寫?(重寫初衷)

利用新的語言特性

隨着 ES2015 的標準化,JavaScript(正式稱爲 ECMAScript ,縮寫爲 ES)獲得了重大改進,主流瀏覽器終於開始爲這些新特性提供良好的支持。特別是其中一些新特性爲咱們極大提升 Vue 的性能提供了機會。

其中最值得關注的是 Proxy,它容許框架攔截對象上的操做。Vue 的核心功能是可以偵聽用戶定義的狀態變動並響應式的更新 DOM。Vue2 是經過使用 getter 和 setter 替換響應式對象上的屬性來實現的這個功能。換做使用 Proxy 可以消除 Vue 現存的一些限制,例如沒法檢測到新的屬性添加併爲其提供更好的性能。

然而,Proxy 是語言原生的特性,在舊版本的瀏覽器中不能被徹底的支持。爲了使用它,咱們意識到必須調整框架的瀏覽器支持範圍,這是一個突破性的變化 (breaking change),也只能在新的主要版本中發佈。

解決架構問題

在當前代碼庫彙總解決這些問題,重構的風險較大,幾乎等同於重寫

在維護 Vue 2 的過程當中,因爲現有架構的限制,咱們積累了許多難以解決的問題。例如,模板編譯器的編寫方式使適當的 source-map 支持很是具備挑戰性。一樣,雖然 Vue 2 從技術上容許構建針對非 DOM 平臺的更高級別的渲染器,但咱們必須 fork 代碼庫並複製大量代碼,才能實現這一點。要在當前代碼庫中解決這些問題,重構的風險很大,幾乎等同於重寫。

同時,咱們在各類模塊的內部與浮動代碼之間的隱式耦合上積累了技術債,而浮動代碼 (floating code) 彷佛並不屬於任何地方。這使得單獨理解代碼庫的一部分變得更加困難,而且咱們注意到,貢獻者對重要的更改很沒有信心,重寫將使咱們有機會牢記這些注意事項來從新考慮代碼組織。

初始原型階段

咱們於 2018 年末開始對 Vue 3 進行原型設計,其初步目標是驗證這些問題的解決方案的可行性。在此階段,咱們主要致力於爲進一步發展奠基堅實的基礎。

切換到 TypeScript

Vue 2 最初是用純 ES 編寫的。在進入原型開發階段以後不久,咱們意識到類型系統對於這種規模的項目將會很是有幫助。類型檢查極大地減小了在重構期間引入意外錯誤的機會,並有助於貢獻者更自信地進行重要的更改。咱們採用了 Facebook 的 Flow 類型檢查器,由於它能夠逐漸添加到現有的 Plain-ES 項目中。 Flow 在必定程度上有所幫助,可是咱們沒有從中得到咱們但願的最大收益。特別是不斷的變化使升級變得很痛苦。與 TypeScript 和 Visual Studio Code 之間的深度集成相比,對集成開發環境的支持也不理想。

咱們還注意到,用戶愈來愈多地同時使用 Vue 和 TypeScript。爲了支持它們的用例,咱們在不一樣的類型系統下,必須與源代碼分開編寫和維護 TypeScript 聲明。切換到 TypeScript 將使咱們可以自動生成聲明文件,從而減輕了維護負擔。

解耦內部封裝

咱們還採用了 monorepo 設置框架的內部 packages 構成,每一個 package 都具備本身的獨立 API,類型定義和測試用例。咱們但願使這些模塊之間的依賴關係更加明確,從而使開發人員更容易閱讀、理解並進行全部更改。這是咱們努力下降該項目的貢獻障礙並提升其長期可維護性的關鍵。

設置 RFC 流程

到 2018 年末,咱們有了一個使用新的響應式系統和虛擬 DOM 渲染器的工做原型。咱們已經驗證了咱們想要進行的內部體系結構改進,可是隻包含了面向公衆的 API 更改的草稿 (drafts)。是時候將它們變成具體的設計了。

咱們知道咱們必須未雨綢繆。 Vue 的普遍使用意味着突破性變化 (breaking changes) 可能致使用戶大量遷移成本和潛在的生態系統碎片化。爲了確保用戶可以提供有關重大更改的反饋,咱們於 2019 年初採用了 RFC(徵求意見)流程。每一個 RFC 遵循一個模板,各章節重點介紹動機、設計細節以及取捨和權衡策略。因爲此過程是在 GitHub 倉庫中進行的,提案經過 pull requests 形式,所以討論在評論中 (comments) 天然展開。

事實證實,RFC 流程很是有用,它是一個使咱們可以充分考慮潛在變動的全方位的思想框架,而且容許咱們的社區參與設計過程並提交通過深思熟慮的feature requests。

更快更小

性能對於前端框架相當重要

性能對於前端框架相當重要。儘管 Vue 2 具備出色的性能,但經過嘗試新的渲染策略重寫,提供了進一步提高性能的機會。

克服虛擬 DOM 的瓶頸

Vue有一個至關獨特的渲染策略:它提供了相似於 HTML 的模板語法,可是將模板編譯爲可返回虛擬 DOM 樹的渲染函數 (render function)。該框架經過遞歸遍歷兩個虛擬 DOM 樹並比較每一個節點上的每一個屬性來肯定真實 DOM 的哪些部分須要更新。得益於現代 JavaScript 引擎執行的高級優化,所以這種有點蠻力的算法一般很快,可是更新仍然涉及許多沒必要要的 CPU 工做。當您查看的模板中大部分是靜態內容而且只有少許動態綁定時,效率低下尤爲明顯-整個虛擬 DOM 樹仍須要遞歸遍歷以找出更改之處。

幸運的是,模板編譯步驟使咱們有機會對模板進行靜態分析並提取有關動態部分的信息。Vue 2 經過跳過靜態子樹在某種程度上作到了這一點,不過因爲編譯器體系結構過於簡單,難以進行更高級的優化。在 Vue 3中,咱們使用適當的 AST 轉換 pipeline 重寫了編譯器,這使咱們可以以轉換插件的形式編寫編譯時的優化。

有了新的體系結構,咱們但願找到一種儘量減小開銷的渲染策略。一種選擇是放棄虛擬 DOM 並直接生成命令式 DOM 操做,但這將消除直接編寫虛擬 DOM 渲染功能的能力 (render functions),咱們發現該功能對於高級用戶和庫的做者很是有價值。另外,這將是一個突破性的變化 (breaking change)。

其次,最佳的方案是消除沒必要要的虛擬 DOM 樹遍歷和屬性比較,這在更新過程當中每每會帶來最大的性能開銷。爲了實現這一點,編譯器 (compiler) 和運行時 (runtime) 須要協同工做:編譯器分析模板並生成帶有優化提示的代碼 (hints),而運行時將選擇這些提示的代碼並在可能的狀況下采用快速路徑 (fast paths)。這裏有三個主要的優化工做:

首先,在樹級別,咱們注意到,在沒有模板指令的狀況下節點結構保持徹底靜態,模板指令動態地改變了節點結構(例如:v-if 和 v-for)。若是咱們將模板劃分爲由這些結構指令分隔的嵌套「塊」,則每一個塊內的節點結構將再次變得徹底靜態。當咱們更新一個塊中的節點時,咱們再也不須要遞歸遍歷該樹-能夠在平面數組中追蹤該塊內的動態綁定。這種優化經過將咱們須要執行的樹遍歷數量減小了一個數量級,從而避免了虛擬 DOM 的大部分開銷。

其次,編譯器會主動檢測模板中的靜態節點、子樹甚至數據對象,並將其提高到生成代碼中的 render 函數以外。這樣能夠避免在每次渲染上從新建立這些對象,從而大大提升了內存使用率並減小了垃圾回收的頻率。

第三,在元素級別,編譯器還會根據須要執行的更新類型爲具備動態綁定的每一個元素生成一個優化標誌。例如,具備動態類綁定和許多靜態屬性的元素將收到一個標誌,該標誌指示僅用於類型檢查。運行時將獲取這些提示並採用專用的快速路徑。

綜上所述,這些技術大大改善了咱們的渲染更新基準 (benchmarks),有時 Vue 3 佔用的 CPU 時間不到 Vue 2 的十分之一。

(CPU 時間,即執行 JavaScript 計算所花費的時間,不包括瀏覽器 DOM 操做。)

最小化包體積

框架的大小也會影響其性能。這是 Web 應用程序的惟一關注點,由於須要即時下載資源,在瀏覽器解析必要的 JavaScript 以前該應用程序是不可交互的。對於單頁應用程序尤爲如此。儘管 Vue 一直是相對輕量級的(Vue 2 的運行時大小壓縮爲 23 KB),但咱們注意到了兩個問題:

首先,並非每一個人都使用框架的全部功能。例如,一個從不使用 transition 功能的應用仍需下載與 transition 相關的代碼並解析。

其次,當咱們添加新功能時,該框架會無限期地增加。當新功能添加時,咱們不得不爲包的尺寸比例折衷考慮。所以,咱們傾向於框架僅包含大多數用戶使用的功能。

理想狀況下,用戶應該可以在構建時刪除未使用的框架功能的代碼(也稱爲「tree-shaking」),而且只打包使用的代碼部分。這也將使咱們可以發佈一部分用戶會以爲有用的功能,而不會增長其他用戶的成本。

在 Vue 3 中,咱們經過將大多數全局 API 和內部幫助程序移至 ES 模塊導出來,實現了這一目標。這使現代的打包工具能夠靜態分析模塊依賴性並刪除未使用的導出相關的代碼。模板編譯器還會生成友好的 Tree-shaking 代碼,在模板中實際使用了該功能時才導入該功能的幫助程序。

框架的某些部分永遠不會 Tree-shaking,由於它們對於任何類型的應用都是必不可少的。咱們將這些必不可少的部分的度量標準稱爲基準尺寸。儘管增長了許多新功能,但 Vue 3 的基準大小壓縮後約爲 10 KB,不到 Vue 2 的一半。

解決規模需求

咱們還但願提升 Vue 處理大型應用程序的能力。咱們最初的 Vue 設計着重於下降入門門檻以及溫和的學習曲線。可是隨着 Vue 愈來愈普遍地被應用,咱們瞭解到了更多有關項目需求的信息,這些項目包含數百個模塊,而且隨着時間的流逝由數十名開發人員維護。對於這些類型的項目,像 TypeScript 這樣的類型系統以及可複用代碼的能力相當重要,而 Vue 2 在這些領域的支持並不理想。

在設計 Vue 3 的早期階段,咱們嘗試經過提供對使用類編寫組件的內置支持來改善 TypeScript 集成。挑戰在於,咱們須要使類可用的許多語言特性(如類字段和裝飾器)還是提案,而且在正式成爲 JavaScript 一部分以前可能會發生變化。其涉及的複雜性和不肯定性使咱們對添加 Class API 是否真的合理這件事產生懷疑,由於它除了提供 TypeScript 集成稍好以外並沒有其餘功能。

咱們決定研究其餘解決擴展問題的方法。受 React Hooks 的啓發,咱們考慮過公開較低級別的響應式和組件生命週期 API,以實現一種更自由的編寫組件邏輯的方式,稱爲 Composition API。無需經過指定一長串選項來定義組件,Composition API 容許用戶像編寫函數同樣自由表達、組合和複用有狀態組件邏輯,同時還提供了出色的 TypeScript 支持。

咱們對這個想法感到很是興奮。儘管 Composition API 旨在解決特定類別的問題,但從技術上講,僅在編寫組件時纔可使用它。在該提案的初稿(first draft)中,咱們預先暗示可能會在未來的版本中將現有的 Options API 替換爲 Composition API。這致使了社區成員的大量反對,這使咱們得到了寶貴的經驗,即如何清楚地傳達長期計劃和意圖,以及更好地理解用戶的需求。在聽取了咱們社區的反饋以後,咱們對提案進行了徹底的從新設計,從而明確代表 Composition API 將是 Options API的補充和附加。修改後的提案更爲積極,並收到了許多建設性的建議。

尋求平衡

開發人員的配置文件多樣性與用例的多樣性相對應

Vue 擁有超過一百萬的開發人員,有隻瞭解 HTML / CSS 的基礎知識的初學者、從 jQuery 遷移的專業人員、從另外一個框架遷移的資深人士、正在尋找前端解決方案的後端工程師以及處理大規模軟件的架構師。開發人員配置文件的多樣性與用例的多樣性相對應:一些開發人員可能但願將交互性擴展到舊版應用程序上,而另外一些開發人員則可能正在快速處理但維護需求有限的一次性項目中工做;在項目的整個生命週期中,架構師可能不得不該對大型的、多年的項目以及不斷變化的開發商團隊。

在咱們平衡各類因素的同時,Vue 的設計不斷受到這些需求的影響,並不斷適應這些需求。Vue 的口號是「漸進式框架」,封裝了此過程當中產生的分層 API 設計。初學者可使用 <script> 引入 CDN,基於 HTML 的模板和直觀的 Options API 來享受流暢的學習曲線,而專家可使用功能齊全的 CLI,render functions 和 Composition API 處理大型複雜的項目。

要實現咱們的願景,還有許多工做要作-最重要的是,更新周邊生態庫、文檔和工具以確保順利遷移。在接下來的幾個月中,咱們將繼續努力,咱們火燒眉毛地想看看社區將經過 Vue 3 創造出什麼。

❤️愛心三連擊

1.看到這裏了就點個在看支持下吧,你的在看是我創做的動力。

2.關注公衆號前端食堂,你的前端食堂,記得按時吃飯

3.本文已收錄在前端食堂Github github.com/Geekhyt,求個小星星,感謝Star。
公衆號二維碼.jpg

相關文章
相關標籤/搜索