我还是不够了解Vue - 源码初探

Vue目录结构

src
├── compiler        # 编译相关 
├── core            # Vue核心
├── platforms       # 构建平台
├── server          # 服务端渲染
├── sfc             # 解析 .vue 后缀文件代码
├── shared          # 共享的工具代码和常量

Vue的目录可以看出,对于不同模块都区分的非常清楚,这样的设计模式不仅利于开发和维护,也便于开发者阅读源码。目录下的每个模块都值得一读,重点从 Vue 的核心 core 入口开始。

Vue入口

# /src/core/index.js

import Vue from './instance/index'
import { initGlobalAPI } from './global-api/index'
import { isServerRendering } from 'core/util/env'

initGlobalAPI(Vue)

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

Object.defineProperty(Vue.prototype, '$ssrContext', {
  get () {
    /* istanbul ignore next */
    return this.$vnode && this.$vnode.ssrContext
  }
})

Vue.version = '__VERSION__'

export default Vue

主要做了以下事情:

  • 引入Vue,并最终导出
  • 调用initGlobalAPI,初始化全局API
  • 劫持Vue原型上的$isServer属性,修改其get方法,判断是否为服务器渲染
// 其定义如下
export const isServerRendering = () => {
  if (_isServer === undefined) {
    /* istanbul ignore if */
    if (!inBrowser && !inWeex && typeof global !== 'undefined') {
      // detect presence of vue-server-renderer and avoid
      // Webpack shimming the process
      _isServer = global['process'] && global['process'].env.VUE_ENV === 'server'
    } else {
      _isServer = false
    }
  }
  return _isServer
}
  • 修改ssrContext,判断是否为服务器渲染上下文

initGlobalAPI

# /src/core/global-api/index.js

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

  // 2.6 explicit observable API
  Vue.observable = <T>(obj: T): T => {
    observe(obj)
    return obj
  }

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

主要作用就是在Vue上扩展一些全局定义的方法,在Vue的官方文档中的关于全局API的内容都在这。
因为只是初步介绍,这里就不详述了,后续会在别的文章介绍。

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) {
  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的定义,它其实就是一个构造函数,我们平时在项目中 new Vue() 就是从这里开始的。
后续将会详细介绍Vue初始化的过程,这里值得一提的是,Vue并没有使用ES6 Class的语法,而是通过扩展Vue构造函数的prototype,充分利用javascript原型的设计实现了模块化,可以看到下面很多mixin都是去扩展。就像前面说的,这样的代码设计非常利于阅读和维护。

相关推荐