1. 程式人生 > >大白話Vue源碼系列(01):萬事開頭難

大白話Vue源碼系列(01):萬事開頭難

重要性 important 阮一峰 time 映射 處理 gpo 知識 catalog

閱讀目錄
  • Vue 的源碼目錄結構
  • 預備知識
  • 先撿軟的捏

Angular 是 Google 親兒子,React 是 Facebook 小正太,那咱為啥偏偏選擇了 Vue 下手,一句話,Vue 是咱見過的最對脾氣的 MVVM 框架。之前也使用過 knockout,angular,react 這些框架,但都沒有讓咱產生 follow 的沖動。直到見到 Vue,簡直是一見鐘情啊。

Vue 的官方文檔已經對 Vue 如何使用提供了最好的教程,建議 Vue 新手直接去官網學習,而不要在網上找些質量參差不齊的文檔去看,以免誤人子弟。中文版 和 英文版 文檔寫的都很地道,畢竟是國產,中文文檔真心贊。不誇張地說,中文文檔咱已經看了不下 5 遍了,每次都有收獲,第一遍看的很慢,邊看邊做,之後就非常快了,主要都是掃讀。英文的咱也不是看不了,只是速度問題,沒必要較這個勁。值得一提的是,Vue 每次版本更新官方文檔迅速都會跟進到最新,所以說 Vue 的官方文檔是學習 Vue 的不二之選。

本系列的目的不是介紹如何使用 Vue,而是希望把 Vue 的源碼實現思路簡單清晰地描繪出來,從而摸清一個 MVVM 框架是如何工作的,並從中學習封裝輪子(庫或框架)的各種實用技巧。文章中的不足和欠缺之處,請大家多多指教/抱拳。

Vue 版本:2.5.9

Vue 的源碼目錄結構

如果直接去看 Vue 生成的代碼文件 Vue.js,代碼足足有上萬行。這樣去研究源碼肯定是行不通的,也是不明智的。從 Vue 項目的目錄結構入手是個不錯的選擇,這麽大的項目,一個好的目錄結構對開發和維護的重要性不言而喻。

Vue 源碼目錄如下:

技術分享圖片

Vue 源碼目錄

各目錄和文件功能:

  • compiler
    此目錄存放編譯模板相關的代碼,用於將 html 模板編譯成 Vue 的 render 函數。
  • runtime
    此目錄存放 Vue 生命周期內使用的相關代碼,負責 Vue 實例的創建,視圖渲染和處理虛擬 DOM 等等一切編譯 html 模板之外的事情。
  • server
    這裏存放 Vue 服務端渲染(SSR)需要使用的代碼。
  • util
    這裏存放一些其他模塊共用的工具函數。
  • entry-compiler.js
    該文件是一個提供編譯 html 模板相關接口的模塊,通常用於為 Vue 編寫的構建插件,比如 vue-loadervueify
  • entry-runtime.js
    用於構建僅包含運行時的文件,不具備編譯 html 模板功能。
  • entry-runtime-with-compiler.js
    用於構建同時包含編譯器和運行時的全功能文件。
  • entry-server-basic-renderer.js 和 entry-server-renderer.js
    用於構建服務端渲染可用的文件。

可見 Vue 按照功能塊對整個項目進行了目錄拆分,每個目錄負責一塊功能,接下來就可以從這些 entry 文件入手按照 模塊依賴 進行由淺及深,從整體到局部的深入剖析。

在繼續之前咱們可以先看一下由上面這些源代碼構建出來的可用文件是怎麽樣的。

Vue 構建生成的目錄如下:

技術分享圖片

Vue 構建生成的目錄

各文件功能:

UMDCommonJSES Module
Fullvue.jsvue.common.jsvue.esm.js
Runtime-onlyvue.runtime.jsvue.runtime.common.jsvue.runtime.esm.js

表格中的術語解釋:

  • Full:包含編譯器和運行時的全部功能。
  • Runtime-only:僅包含運行時。
  • UMD:可通過 <script> 標簽引入直接在瀏覽器中使用,Vue 會暴露一個全局變量 window.Vue。同時適配 require.js 這種 AMD 系統的使用。
  • CommonJS:適配 const Vue = require(‘vue‘) 這種 node 式的模塊系統。
  • ES Module:適配 import Vue from ‘vue‘ 這種 es6 提供的模塊系統。

這些被構建出來的文件才是咱們在實際項目中可以直接使用的文件。

是用 Full 還是用 Runtime-only ?
這個需要具體情況具體分析。如果你需要使用 Vue 提供的 html 模板功能,那麽就使用 Full 版本。否則,最好用 Runtime-only 版本,因為它比 Full 版本的文件體積會小上 30% 左右。值得註意的是,*.vue 單文件組件會被 vue-loader 或 vueify 直接構建成 JavaScript,並沒有使用到 Vue 的編譯器,因此可使用 Runtime-only 版本。

預備知識

# Flow

Vue 使用了 Facebook 出品的 flow.js 作為靜態類型檢查工具,所以特意跑到 flow 的官網了解了一下(不然看到一些奇怪的寫法會一臉懵逼),發現其實很簡單,就是在變量或函數簽名的地方加上一些類型註解,而且都是可選項,加不加都行,主要是為了方便開發維護用的。

為什麽選擇 FLow 而不是 TypeScript ?
Vue 是想找一個靜態類型檢查工具以便提高項目的開發效率和可維護性。Flow 和 TypeScript 都提供了靜態類型檢查功能,但 TypeScript 提供了更多的有用功能,靜態類型檢查只是 TypeScript 提供的諸多強大功能裏並不起眼的一個。而 Flow 則不一樣,靜態類型檢查幾乎是它的全部,可以說是典型小而美的實現。可能是本著殺雞焉用牛刀,盡可能降低項目復雜度的想法,Vue 選擇了 Flow 而不是 TypeScript。無獨有偶,Vue 的構建工具選擇了 rollup 而不是 webpack,原因應該也是如出一轍。所以說最強的不一定是最好的,最合適的才是最好的。

# ES6

Vue 的源碼完全使用 ES6 編寫,使得代碼更清晰,更易維護。本系列的所有代碼片段亦全部使用 ES6,不熟悉 ES6 的同學是時候加強學習了,這可是 JavaScript 的未來。如果想系統了解一下 ES6 的話推薦阮一峰老師的 ECMAScript 6 入門 教程。

# Rollup

Vue 使用了 Rollup 作為最後的打包工具。並且使用了 Rollup 的 rollup-plugin-alias 插件,該插件可以為目錄取一個別名,使得在編寫 ES6 代碼 import 模塊時可以使用更短的路徑,而不用每次都小心翼翼地去拼相對路徑,非常方便。如果不了解這一點,在看到 import config from ‘core/config‘ 這種語句時可能會很迷惑,同級目錄下並沒有 core 目錄啊,實際上 core 是 Vue 為其他目錄配置的別名。這個映射表可以在 build/alias.js 文件中找到,映射表中有一條 core: resolve(‘src/core‘)resolve(‘src/core‘) 會解析出 core 目錄的絕對路徑,這其實就是告訴 rollup 在解析 import config from ‘core/config‘ 時從這個絕對目錄中去加載 config.js

先撿軟的捏

從源碼的目錄結構可以看出,Vue 的 runtime 模塊負責的事情很多,代碼量必然也很大,應該是塊難啃的骨頭。而 compiler 則只負責將 html 模板轉換為 Vue 的 render 函數,這一塊應該是水很淺的,因此從這塊入手先吃掉它一部分。

本系列將以每周一篇的速度定時更新,喜歡的小夥伴可以點推薦哦。

大白話Vue源碼系列(01):萬事開頭難