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
都是去扩展。就像前面说的,这样的代码设计非常利于阅读和维护。