1. 程式人生 > >vue原始碼探究---讀vue技術揭祕(1)

vue原始碼探究---讀vue技術揭祕(1)

需要了解

RollUp
Flow

RollUp

Rollup是一個js的模組打包器,可以將小塊程式碼編譯成大塊複雜程式碼,那為什麼這樣做呢,為了降低開發問題時候的複雜度
Tree-shaking(搖樹優化)
除了使用ES6的模組外,Rollup還能靜態分析程式碼中的import
// 使用 ES6 import 語句匯入(import) ajax 函式
import { ajax } from 'utils';
var query = 'Rollup';
// 呼叫 ajax 函式
ajax( 'https://api.example.com?search=' + query ).then( handleResponse );

Vue 原始碼目錄

├── scripts ------------------------------- 構建相關的檔案,一般情況下我們不需要動
│   ├── git-hooks ------------------------- 存放git鉤子的目錄
│   ├── alias.js -------------------------- 別名配置
│   ├── config.js ------------------------- 生成rollup配置的檔案
│   ├── build.js -------------------------- 對 config.js 中所有的rollup配置進行構建
│   ├── ci.sh ----------------------------- 持續整合執行的指令碼
│   ├── release.sh ------------------------ 用於自動釋出新版本的指令碼
├── dist ---------------------------------- 構建後文件的輸出目錄
├── examples ------------------------------ 存放一些使用Vue開發的應用案例
├── flow ---------------------------------- 型別宣告,使用開源專案 [Flow](https://flowtype.org/)
├── packages ------------------------------ 存放獨立釋出的包的目錄
├── test ---------------------------------- 包含所有測試檔案
├── src ----------------------------------- 這個是我們最應該關注的目錄,包含了原始碼
│   ├── compiler -------------------------- 編譯器程式碼的存放目錄,將 template 編譯為 render 函式
│   ├── core ------------------------------ 存放通用的,與平臺無關的程式碼
│   │   ├── observer ---------------------- 響應系統,包含資料觀測的核心程式碼
│   │   ├── vdom -------------------------- 包含虛擬DOM建立(creation)和打補丁(patching)的程式碼
│   │   ├── instance ---------------------- 包含Vue建構函式設計相關的程式碼
│   │   ├── global-api -------------------- 包含給Vue建構函式掛載全域性方法(靜態方法)或屬性的程式碼
│   │   ├── components -------------------- 包含抽象出來的通用元件
│   ├── server ---------------------------- 包含服務端渲染(server-side rendering)的相關程式碼
│   ├── platforms ------------------------- 包含平臺特有的相關程式碼,不同平臺的不同構建的入口檔案也在這裡
│   │   ├── web --------------------------- web平臺
│   │   │   ├── entry-runtime.js ---------- 執行時構建的入口,不包含模板(template)到render函式的編譯器,所以不支援 `template` 選項,我們使用vue預設匯出的就是這個執行時的版本。大家使用的時候要注意
│   │   │   ├── entry-runtime-with-compiler.js -- 獨立構建版本的入口,它在 entry-runtime 的基礎上添加了模板(template)到render函式的編譯器
│   │   │   ├── entry-compiler.js --------- vue-template-compiler 包的入口檔案
│   │   │   ├── entry-server-renderer.js -- vue-server-renderer 包的入口檔案
│   │   │   ├── entry-server-basic-renderer.js -- 輸出 packages/vue-server-renderer/basic.js 檔案
│   │   ├── weex -------------------------- 混合應用
│   ├── sfc ------------------------------- 包含單檔案元件(.vue檔案)的解析邏輯,用於vue-template-compiler包
│   ├── shared ---------------------------- 包含整個程式碼庫通用的程式碼
├── package.json -------------------------- 不解釋
├── yarn.lock ----------------------------- yarn 鎖定檔案
├── .editorconfig ------------------------- 針對編輯器的編碼風格配置檔案
├── .flowconfig --------------------------- flow 的配置檔案
├── .babelrc ------------------------------ babel 配置檔案
├── .eslintrc ----------------------------- eslint 配置檔案
├── .eslintignore ------------------------- eslint 忽略配置
├── .gitignore ---------------------------- git 忽略配置

Vue 不同構建輸出

vue使用Rollup構建,有三種輸出方式,UMD,CommonJS,ESModule,三種構建配置入口相同web/entry-runtime.js,但是輸出格式format不同,cjs,es,umd,每種模組形式又分為執行版和完成版

完整版比執行版多一個compiler(觀察者),作用為編譯器程式碼的存放目錄,將template編譯為render,執行版+Compiler = 完整版

Flow

Flow 是Facebook出品的JS靜態型別檢查工具,Vue.js原始碼就是利用Flow做靜態型別檢查。
Flow是動態型別語言,由於js是動態型別語言,很靈活,但是過於靈活容易寫出隱蔽的錯誤程式碼。所以類檢查是當前動態型別語言的發展趨勢。

Flow的工作方式

  • 型別推斷:通過變數的使用上下文來推斷出變數的型別,根據推斷來檢查型別
  • 型別註釋:事先註釋好我們需要的型別,FLow會基於註釋推斷
型別推斷

不需要任何程式碼修改即可進行型別檢查,會自動推斷變數型別。

function split(str) {
  return str.split(' ')
}

split(11)

在Flow檢查後,會報錯,因為split需要的是字串

型別註釋

不需要編寫型別註釋就能過去反饋。

/*@flow*/

function add(x, y){
  return x + y
}

add('Hello', 11)

Flow檢查不出錯誤,但是我們可以通過型別註釋來指明期望的型別,型別註釋以冒號:開頭,可以在函式引數,返回值和變數宣告中使用。

/*@flow*/

function add(x: number, y: number): number {
  return x + y
}

add('Hello', 11)

這樣就可以檢查到型別。

陣列
/*@flow*/

var arr: Array<number> = [1, 2, 3]

arr.push('Hello')

陣列型別註釋的格式是Array,T表示陣列中每項的資料型別。

類和物件

class Bar {
  x: string;           // x 是字串
  y: string | number;  // y 可以是字串或者數字
  z: boolean;

  constructor(x: string, y: string | number) {
    this.x = x
    this.y = y
    this.z = false
  }
}

var bar: Bar = new Bar('hello', 4)

var obj: { a: string, b: number, c: Array<string>, d: Bar } = {
  a: 'hello',
  b: 11,
  c: ['hello', 'world'],
  d: new Bar('hello', 3)
}

類的型別註釋格式,可以對類自身的屬性做型別檢查,也可以對建構函式的引數做型別檢查,y中間使用|,表示y的型別既可以用字串也可用數字

Null

若想用型別T可以為null或undefined,可以寫成?T格式:

/*@flow*/

var foo: ?string = null