Vue源碼該如何入手?

前言

這是一個對Vue.js源碼解析的系列,會持續更新,歡迎關注;話很少說,下面咱們就從怎麼讀Vue.js源碼開始。html

一. 源碼目錄

首先咱們先看看Vue.js源碼的項目結構:Vue.js源碼GitHubvue

咱們先了解一下src這個目錄的各模塊分工:node

src
├── compiler        # 編譯相關 
├── core            # 核心代碼 
├── platforms       # 不一樣平臺的支持
├── server          # 服務端渲染
├── sfc             # .vue 文件解析
├── shared          # 共享代碼
複製代碼

1. compiler

compiler模塊包含Vue.js了全部編譯相關的代碼。它包括把模板解析成AST語法樹,AST語法樹優化,代碼生成等功能。webpack

2. core

core目錄包含了Vue.js的核心代碼,包括內置組件、全局 API 封裝,Vue 實例化、觀察者、虛擬 DOM、工具函數等。git

3. platform

Vue.js是一個跨平臺的MVVM框架,它能夠跑在 web上,也能夠配合weex跑在native客戶端上。platformVue.js的入口,會分別打包成運行在 web上和weex上的Vue.jsgithub

4. server

這是與服務端渲染相關的部分,這部分代碼是跑在服務端的Node.jsweb

5. sfc

一般咱們開發Vue.js都會藉助webpack構建,而後經過.vue單文件來編寫組件,這個模塊的功能就是將.vue文件內容解析成一個 JavaScript的對象。npm

6. shared

這裏是Vue.js定義的一些共享工具方法,會供以上模塊所共享。json

大概瞭解了以上模塊功能後,咱們就知道了對於web端的源碼,咱們主要分析的就是core模塊。weex

二. 源碼的構建入口

想一想日常咱們使用vue的時候是經過npm來安裝使用的,那說明Vue.js其實就是一個 node包,但它是基於Rollup構建的,但咱們也能夠用webpack的一些打包思路去理解它,若是對webpacknode包還不太瞭解的同窗能夠看看我以前寫的webpack4.x最詳細入門講解不會發布node包?進來看看

簡單理解的話就是Vue.js經過構建工具將其打包,這個包會導出一個Vue構造函數供咱們使用。

因此咱們從Vue.js源碼中的package.json文件入手,由於其包含了打包的一些配置記錄,主要了解兩個地方:

1. 導出口

"module": "dist/vue.runtime.esm.js"
複製代碼

這個配置能夠理解爲出口或者入口,理解爲出口時就是指它會導出一個Vue構造函數供咱們使用;理解爲入口的話就從這個vue.runtime.esm.js開始集成Vue.js作須要的代碼。

2. 打包入口

"scripts": {"build": "node scripts/build.js"}
複製代碼

能夠理解爲打包入口,會經過build.js找到Vue.js所須要的依賴代碼,而後對其進行打包,全部咱們能夠從這裏入手,去scripts/build.js路徑下的build.js文件中看看:

// scripts/build.js 
let builds = require('./config').getAllBuilds()
...
build(builds)
複製代碼
// scripts/config.js
const builds = {
  // Runtime only (CommonJS). Used by bundlers e.g. Webpack & Browserify
  'web-runtime-cjs': {
    entry: resolve('web/entry-runtime.js'),
    dest: resolve('dist/vue.runtime.common.js'),
    format: 'cjs',
    banner
  },
  // Runtime+compiler CommonJS build (CommonJS)
  'web-full-cjs': {
    entry: resolve('web/entry-runtime-with-compiler.js'),
    dest: resolve('dist/vue.common.js'),
    format: 'cjs',
    alias: { he: './entity-decoder' },
    banner
  },
  // Runtime only (ES Modules). Used by bundlers that support ES Modules,
  // e.g. Rollup & Webpack 2
  'web-runtime-esm': {
    entry: resolve('web/entry-runtime.js'),
    dest: resolve('dist/vue.runtime.esm.js'),
    format: 'es',
    banner
  },
  // Runtime+compiler CommonJS build (ES Modules)
  'web-full-esm': {
    entry: resolve('web/entry-runtime-with-compiler.js'),
    dest: resolve('dist/vue.esm.js'),
    format: 'es',
    alias: { he: './entity-decoder' },
    banner
  },
  // runtime-only build (Browser)
  'web-runtime-dev': {
    entry: resolve('web/entry-runtime.js'),
    dest: resolve('dist/vue.runtime.js'),
    format: 'umd',
    env: 'development',
    banner
  },
  // ...
}

exports.getAllBuilds = () => Object.keys(builds).map(genConfig)
複製代碼

以上邏輯其實就是從配置文件config.js中讀取配置,再對構建配置作過濾,進而根據不一樣配置構建出不一樣用途的Vue.js,其中就有web使用的兩個版本:Runtime OnlyRuntime + Compiler

3. Runtime Only

在使用Runtime Only版本的Vue.js的時候,一般須要藉助如webpackvue-loader工具把.vue文件編譯成JavaScript,由於是在編譯階段作的,因此它只包含運行時的Vue.js代碼,所以代碼體積也會更輕量。

4. Runtime + Compiler

若是沒有對代碼作預編譯,但又使用了Vuetemplate屬性並傳入一個字符串,則須要在客戶端編譯模板,因此須要帶有編譯器的版本,即Runtime + Compiler

由於後續系列咱們會將到編譯模塊,全部咱們就從帶編譯器的版本入手,即以上入口是entry: resolve('web/entry-runtime-with-compiler.js'),的文件,根據源碼的路徑解析咱們獲得最終的文件路徑是src/platforms/web/entry-runtime-with-compiler.js

// src/platforms/web/entry-runtime-with-compiler.js
import Vue from './runtime/index'
// ...
export default Vue
複製代碼

能夠看到這個文件不是定義Vue構造函數的地方,也是從其餘文件引入,而後再加工導出,那咱們從./runtime/index這個文件繼續找:

// src/platforms/web/runtime/index
import Vue from 'core/index'
// ...
export default Vue
複製代碼

依舊如此……,繼續往上找,最終通過幾回查找,在src/core/instance/index.js中能夠看到Vue的真身:

// src/core/instance/index.js
import { initMixin } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import { warn } from '../util/index'

function Vue (options) {
  // 判斷是不是開發環境且必須是new調用
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  // new一個實例時會調用_init方法,該方法在下面的initMixin(Vue)中有定義
  this._init(options)
}

initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)

export default Vue
複製代碼

因此到此咱們終於看到了Vue的廬山真面目,能夠看到Vue是一個構造函數,且通過了一系列的Mixin,進而在Vue的原型上拓展方法。

最後

經過以上梳理,咱們大概瞭解到了咱們平時使用的Vue是怎麼來的,後續系列會繼續對源碼進行梳理,若是對你的有幫助的話歡迎來波關注!

相關參考:Vue.js源碼全方位深刻解析

相關文章
相關標籤/搜索