用vue3公開的思路從0實現最簡化的vue(05-02更新)

名詞解釋

  1. 瀏覽器標準:本文中做爲es六、css三、h5的統稱

咱們爲何要學習vue的實現

咱們用vue,是由於它是當前業界最佳的解決方案之一,但前端技術方案迭代及工業標準化發展的浪潮,大機率不會在vue這裏到達終點。css

jquery沒有死,它的基因已經注入瀏覽器標準。而webcomponent shadow dom的靈感,一樣有受到vue和react的vdom技術的啓發。固然vue也在進化,但要知道,vue的競爭對手,並非react,而是瀏覽器的標準化進程。當webcomponent成爲主流,咱們如今津津樂道的vdom技術也就完成了過渡的使命。html

因此咱們要有危機感和好奇心,不能過渡依賴vue。咱們須要搞清楚在Vue的黑盒中,都作了什麼magic。同時,咱們也能學習到不少現代軟件工程的方法和設計模式,好比tdd、代理模式、觀察者模式、封裝和解耦的藝術。前端

Vue源碼爲何難讀

  1. 功能繁多

咱們讀vue源碼的目的,首先是想了解全貌及部分核心feature的實現,好比雙向綁定、vnode渲染等。而Vue源碼中包含了太多非核心代碼,好比keep alive、dynamic component、functional component等,這些並非不重要,僅僅是咱們暫時對它的實現並不太感興趣,這些代碼的干擾會阻礙咱們對核心部分的理解。vue

  1. 向後兼容

Vue源碼中包含大量向後兼容代碼,但隨着瀏覽器標準從主流框架中吸收精華,以及主流瀏覽器向瀏覽器標準的靠攏,vue做爲框架所承擔的責任會愈來愈小,舉個最簡單的例子,用ES6的Proxy實現雙向綁定,就比Vue2.x中defineProperty的hack作法要簡潔不少。而當webcomponent火候成熟,vue甚至連vdom都不用作了。因此vue3的實現必定會比vue2簡單,這已是官方肯定的。我判斷vue4的實現必定會更精簡,而這個趨勢一直持續到vue退出歷史舞臺。node

爲何要從0寫一個vue

既然咱們要學習vue的實現,而vue的源碼又包含太多的噪音,難以梳理。縱觀全網,雖然源碼分析的文章和教程層出不窮,但思路大多依然埋沒在vue代碼的複雜細節中。那麼,咱們爲什麼不幹掉不感興趣的功能,不care瀏覽器兼容性,只用最新的技術,撥開迷霧去寫一個最簡化的Vue呢?react

此項目將按Vue3.0公開的思路,用測試驅動開發的方法,一步一步寫一個最簡化的Vue,我會盡可能確保每個commit都容易理解。建議跟隨下面步驟作,你將會對Vue有個清晰的理解。jquery

測試驅動開發~why?

軟件工程上,按個人理解,徹底自上而下的設計(瀑布模型),已是過期的方法。即便超大型計算機項目,好比操做系統級別的工程,也是宏觀自上而下,微觀上下結合(敏捷開發)。而TDD是一種上下結合的編程實踐,對於每一個模塊,首先設計測試用例,再寫代碼實現出來。有如下好處:css3

  1. 控制質量,便於迴歸測試,提升開發效率
  2. test case即文檔
  3. 粗略的頂層設計後(包括產品設計和技術設計),便可自下而上開始編程,避免過渡設計

步驟

因爲tdd具備強大的test case即文檔的基因,因此要理解每一步作了什麼事情,只須要看對應的test case代碼便可。git

下面每步將按diff的形式給出,必要的地方會加comment。大段總體的闡述會寫在diff頁面的底部評論區,針對某段代碼的comment會穿插其中。歡迎留言和提issue。es6

階段1: Basic

這部分,咱們從0作起,實現一些基礎feature,不求作到完善

  1. TDD環境搭建

  2. Data代理

  3. 實現$watch

  4. html原生元素渲染

  5. 支持method

  6. 支持lifecycle

  7. html原生元素事件監聽

  8. 實現mvvm

  9. 階段1成果:Basic Demo

運行npm run test後點擊彈出瀏覽器頁面中的DEBUG按鈕便可看到效果

階段2: 完善mvvm

這部分咱們完善mvvm到實現vue2.x的全部feature,並實現vue3.0公開的一個重要feature, 官方說法是"Detection of property addition / deletion",在vue2.x中,咱們須要用$set。

  1. [mvvm]data支持深層object

  2. [mvvm]data中object支持新增屬性

  3. [mvvm]data中object支持刪除屬性

  4. [mvvm]支持array

  5. 階段2成果:mvvm in depth demo

運行npm run test後點擊彈出瀏覽器頁面中的DEBUG按鈕便可看到效果

  1. 簡單重構和補充註釋

整理心情,再出發

階段3: 支持組件

  1. 支持屬性

  2. 實現組件渲染

  3. 實現event&action

階段4: Computed & watch

  1. 計算屬性

  2. 實現watch

  3. 重構:優雅實現代理和依賴收集

  4. 實現$nextTick

  5. 實現Watcher調度

爲了解決改變多個data會觸發屢次render的問題

var cb = jasmine.createSpy('cb');

var vm = new Vue({
  data () {
    return {
      a:1,
      b:2,
    }
  },
  render (h) {
    cb()
    return h('p', null, this.a + this.b)
  }
}).$mount()

expect(cb).toHaveBeenCalledTimes(1)

vm.a = 10
vm.b = 11
setTimeout(_ => {
  expect(cb).toHaveBeenCalledTimes(2) // change 'a' and 'b' only trigger one render
  done()
})
複製代碼

Todo list

  1. Patch

  2. Scoped Slot

補充

virtual dom vs shadow dom

上面對於virtual dom和shadow dom有些混淆,爲了避免誤導你們,這裏推薦兩篇文章

  1. develoger.com/shadow-dom-…

  2. svelte.dev/blog/virtua…

因此,將來vue的發展有兩種可能:

  1. 可能還會作virtual dom,但virtual dom實際渲染出來會是一個web component,如今vue的scoped css,也將被shadow dom取代。

  2. 但還有一種可能。virtual dom存在的意義是因爲考慮到操做dom開銷大,因此要merge對dom操做。但操做shadow dom會快不少,全部我對將來virtual dom是否還有必要保持懷疑。

做者其它文章

  1. ES6類繼承原理及缺陷
相關文章
相關標籤/搜索