vue2.x源码解析四——1.入口文件

1.从package.json文件开始

由上一节的学习,我们应该已经基本明白了Vue源码的整个构建的基本过程,下面我们来学习和了解Vue的入口文件

1.1 npm run dev

还是要看根目录下的package.json文件。这里我们只看第一个,也就是npm run dev所执行的命令。

"dev": "rollup -w -c scripts/config.js --environment TARGET:web-full-dev",
  1. 由这行命令我们看到,用到的构建工具是rollup,我们在上一节已经讲到了,我们只需要知道它是一个类似于webpack的打包工具就行了,
  2. 接着 scripts/config.js,就知道了需要运行scripts/config.js了
  3. web-full-dev 是向scripts/config.js文件传递的参数

1.2 scripts/config.js

这个文件我们上一节也讲到了,他会根据传入参数的不同,而根据不同版本的Vue.js形成构建工具rollup的不同配置

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
  },
  ...
  ...
  ...
}

function genConfig (opts) {
  ...
}

if (process.env.TARGET) {
  module.exports = genConfig(builds[process.env.TARGET])
} else {
  exports.getBuild = name => genConfig(builds[name])
  exports.getAllBuilds = () => Object.keys(builds).map(name => genConfig(builds[name]))
}

我们看到它调用了getConfig(builds[process.env.TARGET]),getConfig用于生成rollup的配置文件。builds是一个对象,获取它的process.env.TARGET值,在package.json中,我们看到dev中有TARGET:web-full-dev参数。
根据web-full-dev这个参数,我们到找到该版本的Vue.js的相关配置,配合alias.js这样入口文件我们就找到了,也就是/src/platforms/web/entry-runtime-with-compiler.js。

2.入口文件

2.1 寻找Vue对象的所在

入口文件:/src/platforms/web/entry-runtime-with-compiler.js。
在文件中我们看到:

import Vue from './runtime/index'

src/platforms/web/runtime/index.js:

import Vue from 'core/index'

src/core/index.js:

import Vue from './instance/index'

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) {
  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)
}

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

export default Vue

至此我们找到了Vue对象的所在。

2.2分析Vue对象

src/core/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)
}

首先判断如果是不是生产环境,且不是通过new关键字来创建对象的话,就在控制台打印一个warning,之后调用了this._init(options)函数。
下面的几个函数,分别在Vue.prototype原型上绑定了一些实例方法,Vue实例方法

// _init
initMixin(Vue)  
// $set$delete$watch
stateMixin(Vue)
// $on$once$off$emit
eventsMixin(Vue)
// _update、$forceUpdate$destroy
lifecycleMixin(Vue)
// $nextTick、_render、以及多个内部调用的方法
renderMixin(Vue)

也许有同学会问,为何没有采用ES6的class,而是采用的ES5的new构造函数的方法,那是因为vue源码中需要向vue的prototype添加许多的方法,ES6操作起来就没有那么容易了,ES5的话写起来要简单许多,而且可以将不同的原型的方法写在不同的js中,方便管理。
这里写图片描述

2.3 initGlobalAPI

我们按照刚才所提到的文件引入顺序一步步来看。src/core/instance/index.js执行之后,是src/core/index.js文件

initGlobalAPI(Vue)

Object.defineProperty(Vue.prototype, '$isServer', {
  get: isServerRendering
})

Vue.version = '__VERSION__'

该文件首先调用了initGlobalAPI,引自src/core/global-api/index.js
Vue.prototype[$isServer]属性,用于判断是不是服务端渲染。

2.3.1 扩展全局的静态方法:

src/core/global-api/index.js中定义了给 Vue 这个对象本身扩展全局的静态方法

export function initGlobalAPI (Vue: GlobalAPI) {
  // config
  const configDef = {}
  configDef.get = () => config
  if (process.env.NODE_ENV !== 'production') {
    configDef.set = () => {
      warn(
        'Do not replace the Vue.config object, set individual fields instead.'
      )
    }
  }
  Object.defineProperty(Vue, 'config', configDef)

  // exposed util methods.
  // NOTE: these are not considered part of the public API - avoid relying on
  // them unless you are aware of the risk.
  Vue.util = {
    warn,
    extend,
    mergeOptions,
    defineReactive
  }

  Vue.set = set
  Vue.delete = del
  Vue.nextTick = nextTick

  Vue.options = Object.create(null)
  ASSET_TYPES.forEach(type => {
    Vue.options[type + 's'] = Object.create(null)
  })

  // this is used to identify the "base" constructor to extend all plain-object
  // components with in Weex's multi-instance scenarios.
  Vue.options._base = Vue

  extend(Vue.options.components, builtInComponents)

  initUse(Vue)
  initMixin(Vue)
  initExtend(Vue)
  initAssetRegisters(Vue)
}

上面引入了全局的config,在src/core/config.js
这里就是在 Vue 上扩展的一些全局方法的定义,Vue 官网中关于全局 API 都可以在这里找到,Vue.util 暴露的方法最好不要依赖,因为它可能经常会发生变化,是不稳定的。

3.总结

  1. 我们找到了vue构造函数,并知道了向vue原型中添加了很多实例方法
  2. 知道了通过 initGlobalAPI 向vue中添加了很多的静态方法

猜你喜欢

转载自blog.csdn.net/haochangdi123/article/details/80873734