學習vue源碼時,咱們首先須要看的是package.json文件,該文件裏配置了vue的依賴以及開發環境和生產環境的編譯的啓動腳本等其餘信息。首先咱們須要關注的是script。咱們這裏先看第一個dev腳本:vue
"dev": "rollup -w -c scripts/config.js --environment TARGET:web-full-dev"
咱們能夠看到vue是採用了rollup編譯的腳本,而後對應的查看其配置文件config.jsnode
const builds = { ... // Runtime+compiler development build (Browser) 'web-full-dev': { entry: resolve('web/entry-runtime-with-compiler.js'), dest: resolve('dist/vue.js'), format: 'umd', env: 'development', alias: { he: './entity-decoder' }, banner }, ... }
在該文件中咱們能夠找到web-full-dev的配置項,而且知道其編譯的文件爲'web/entry-runtime-with-compiler.js'
那麼咱們就須要去找到該文件了。
咱們能夠發現entry-runtime-with-compiler.js的其中有一行代碼是:web
import Vue from './runtime/index'
而後繼續跟着代碼往上找,咱們會發現仍是嵌套了好幾層,最後在'/instance/index'中找到咱們vue的定義:最終其路勁以下:json
/src/platforms/web/web-runtime-with-compiler.js => /src/platforms/web/runtime/index.js => /src/core/index.js => /src/core/instance/index.js
最終咱們在instance/index.js上找到了vue的廬山真面目,他的構造函數及其簡單:瀏覽器
function Vue (options) { if (process.env.NODE_ENV !== 'production' && !(this instanceof Vue) ) { warn('Vue is a constructor and should be called with the `new` keyword') } this._init(options) }
咱們能夠發現它並無使用class的,只是一個普通的構造函數,經過 !(this instanceof Vue) 來強制使用new來構建。
之因此不採用class,我的理解是爲了更好的把代碼拆分。原型上的方法只須要經過prototype來添加。以下weex
initMixin(Vue) // 這裏主要註冊了_init stateMixin(Vue) // $set,$delete,$watch eventsMixin(Vue) // $on, $once, $off, $emit lifecycleMixin(Vue) // _update, $forceUpdate,$destroy renderMixin(Vue) // $nextTick, _render
這邊都是基於在Vue上擴展方法,這樣就把代碼分離開發,方便維護。不須要所有寫到Vue函數內部。
而後咱們往回走,咱們能夠看到/src/core/index.js 中dom
initGlobalAPI(Vue) Object.defineProperty(Vue.prototype, '$isServer', { get: isServerRendering }) Object.defineProperty(Vue.prototype, '$ssrContext', { get () { /* istanbul ignore next */ return this.$vnode && this.$vnode.ssrContext } }) Object.defineProperty(Vue, 'FunctionalRenderContext', { value: FunctionalRenderContext }) Vue.version = '__VERSION__'
該文件中主要就是註冊全局API,以供咱們內部或外部使用
再往上/src/platforms/web/runtime/index.js,咱們能夠看到函數
// install platform specific utils Vue.config.mustUseProp = mustUseProp Vue.config.isReservedTag = isReservedTag Vue.config.isReservedAttr = isReservedAttr Vue.config.getTagNamespace = getTagNamespace Vue.config.isUnknownElement = isUnknownElement // install platform runtime directives & components extend(Vue.options.directives, platformDirectives) extend(Vue.options.components, platformComponents) // install platform patch function Vue.prototype.__patch__ = inBrowser ? patch : noop // 用於把vNode顯示到dom上的方法,這邊要區分是瀏覽器環境仍是weex環境 // public mount method Vue.prototype.$mount = function () { ..... } // 把dom掛在到頁面上
這邊就是註冊一些全局的工具,以及patch方法
那麼再往上:src/platforms/web/web-runtime-with-compiler.js, 這個文件中主要就是重寫$mount工具
const mount = Vue.prototype.$mount Vue.prototype.$mount = function ( ){ ... }
那麼爲何要重寫呢?原來在runtime裏面的$mount方法是沒有編譯功能的,而最後一個重寫就是增長了編譯。
在vue腳手架咱們會讓咱們選擇哪一個版本:以下圖oop
這就是2個版本的區別,是否包含編譯功能。一個是完整版,一個是運行時。
vue官方屬於解釋了:
完整版:同時包含編譯器和運行時的版本。 編譯器:用來將模板字符串編譯成爲 JavaScript 渲染函數的代碼。 運行時:用來建立 Vue 實例、渲染並處理虛擬 DOM 等的代碼。基本上就是除去編譯器的其它一切。 若是你須要在客戶端編譯模板 (好比傳入一個字符串給 template 選項,或掛載到一個元素上並以其 DOM 內部的 HTML 做爲模板),就將須要加上編譯器,即完整版: // 須要編譯器 new Vue({ template: '<div>{{ hi }}</div>' }) // 不須要編譯器 new Vue({ render (h) { return h('div', this.hi) } })
重寫$mount方法就是對template就好了編譯轉換爲render方法
好了這邊就簡要的介紹了vue的入口。
您的點贊是我繼續努力的動力!