重读Vue源码系列三—— “一无所有”的Vue构造函数

891 阅读3分钟

一、例子中引用的dist目录下的vue.js源文件入口


上一篇重读Vue源码系列二 —— 如何调试Vue源码中详细介绍了vue.js的生成过程,并且我们知道了vue.js源码的入口文件就是web/entry-runtime-with-compiler.js,真实的路径是src/platforms/web/entry-runtime-with-compiler.js

const builds = {
   // Runtime+compiler production build  (Browser)
  'web-full-prod': {
    entry: resolve('web/entry-runtime-with-compiler.js'),
    dest: resolve('dist/vue.min.js'),
    format: 'umd',
    env: 'production',
    alias: { he: './entity-decoder' },
    banner
  }
}

这样我们就可以沿着入口文件去查找Vue的构造函数了。

二、Vue构造函数到底在哪里?


  • 我们从入口src/platforms/web/entry-runtime-with-compiler.js开始查找,在该文件我们看到了这行代码import Vue from './runtime/index', 且把Vueexport出去了, 这其实也是我们平常使用的new Vue()的Vue对象,但是在这个文件并没有发现Vue构造函数的定义。
// /src/platforms/web/entry-runtime-with-compiler.js
import config from 'core/config'
import { warn, cached } from 'core/util/index'
import { mark, measure } from 'core/util/perf'

import Vue from './runtime/index' //vue构造函数
import { query } from './util/index'
import { compileToFunctions } from './compiler/index'
import { shouldDecodeNewlines, shouldDecodeNewlinesForHref } from './util/compat'

此处省略......

//最后export出去
export default Vue
  • 沿着import Vue from './runtime/index'继续查找,在这里也没有发现Vue构造函数的定义,但是我们看到了Vue是从'core/index'引进来的。
/src/platforms/web/runtime/index.js

import Vue from 'core/index' 

  • 继续沿着import Vue from 'core/index'查找,如果对webpack熟悉的话,会知道'core/index'使用的是alias,方便我们引入文件,我们找到webpack的配置文件/vue/scripts/alias.js
module.exports = {
  vue: resolve('src/platforms/web/entry-runtime-with-compiler'),
  compiler: resolve('src/compiler'),
  core: resolve('src/core'),
  shared: resolve('src/shared'),
  web: resolve('src/platforms/web'),
  weex: resolve('src/platforms/weex'),
  server: resolve('src/server'),
  sfc: resolve('src/sfc')
}

'core/index'其实就是'src/core/index'

// src/core/index
import Vue from './instance/index'
import { initGlobalAPI } from './global-api/index'
import { isServerRendering } from 'core/util/env'
import { FunctionalRenderContext } from 'core/vdom/create-functional-component'

这个文件还是没有Vue的构造函数,我们继续沿着import Vue from './instance/index'查找

  • 继续查找'./instance/index'文件
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) {//options就是我们new Vue(options)中的option
  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)
}
console.info(`=====Vue最原始构造函数,此时一无所有`);


initMixin(Vue) //prototype_init  传递Vue的目的是为了共用一个Vue类
console.info(`=====VueinitMixin Finish Vue.prototype._init=`,Vue.prototype._init);
stateMixin(Vue) 
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue) //原型添加$nextSick,_render
console.log(`core instance index.js`);
export default Vue

这样,我们在这里终于找到了Vue的构造函数,但是会发现它真的是一无所有,里面就一行看不懂的代码 this._init(options),那我们平时用的那么多的全局API、生命周期钩子、实例方法等都在哪定义的呢?

我们将会在接下来的文章一一介绍~

三、总结


通过前两篇重读Vue源码系列一 —— 目录结构重读Vue源码系列二 —— 如何调试Vue源码以及本篇文章的介绍,我们对Vue源码的目录结构、Vue.js的构建过程以及Vue构造函数的定义都有了基本了解,也找到了Vue的构造函数的源头。

function Vue (options) {//options就是我们new Vue(options)中的option
  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)
}

其实接下来的所有内容都是在完善这个'一无所有'的Vue对象,最终成为我们使用Vue。

下一篇将会介绍重读Vue源码系列四—— “一无所有”的Vue如何实现全局API以及实例属性以及后续的源码讲解计划~