- 一、运行调试命令
- 二、找主文件
- 三、src/core/instance/index.js
- 四、src/core/index.js
- 五、src/platforms/web/runtime/index.js
- 六、src/platforms/web/entry-runtime-with-compiler.js
- 结语
vue源码阅读,Vue构造函数的加工
一、运行调试命令
npm run dev
- windows10下可能会遇到
Could not load xxx\xxx/
的情况,可使用npm i npm update rollup-plugin-alias@1.4.0
升级的方式解决。 - 打包后sourceMap只能对应到压缩前的代码,而不能对应值合并前的各个模块,此时可去
\build\config.js
,在genConfig
函数的config
变量加一个属性sourceMap: true
。const config = { input: opts.entry, // xxxxx sourceMap: true, // xxxxx }
当前项目已做以上处理。 参考
二、找主文件
根据rollup配置的entry和import的引入顺序
- build/config.js ->
- src/platforms/web/entry-runtime-with-compiler.js ->
- src/platforms/web/runtime/index.js ->
- src/core/index.js ->
- src/core/instance/index.js
备注
- 是构建文件入口。
- 根据运行平台(和你的构建指令也有关系)不同进行不同配置的入口。
- 就要找到了,此文件内对
Vue
做了平台相关的配置。 - 找到了,在
Vue
上添加了version
,添加了options{components, directive, filter})
- 我们先看这个,然后按照5、4、3、2、1的顺序看源代码中都对Vue做了哪些处理。
三、src/core/instance/index.js
注意到有一个构造函数和五个函数的调用。
// 构造函数
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')
}
// new 调用Vue构造函数后进行_init
this._init(options)
}
// 5个函数的调用
initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
可以看到的是构造函数中使用了this instanceof Vue
做了this的判断,为非的情况下,给出警告。后面调用this._init(options)
根据传入配置进行实例的构造。
5个函数的调用,从函数的命名上我们也能看出来分别是初始化相关、数据状态相关、事件相关、声明周期相关、渲染相关。 我们先一个个的看这5个函数
initMixin
Vue.prototype._init = function (options?: Object) {}
内部对Vue的原型上添加了_init
方法,就是上面构造函数最后调用的方法。
stateMixin
Object.defineProperty(Vue.prototype, '$data', dataDef)
Object.defineProperty(Vue.prototype, '$props', propsDef)
Vue.prototype.$set = set
Vue.prototype.$delete = del
Vue.prototype.$watch = function (){}
内部对Vue的原型上添加了四个属性$data
、$props
、$set
、$delete
、$watch
,其中$data
、$props
因为有只读方面的限制,所以使用Object.defineProperty
的方式定义,其中各自的xxxDef对set
和get
做了处理。
eventsMixin
Vue.prototype.$on = function () {}
Vue.prototype.$once = function () {}
Vue.prototype.$off = function () {}
Vue.prototype.$emit = function () {}
Vue原型上添加了四个事件相关的方法。
lifecycleMixin
Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {}
Vue.prototype.$forceUpdate = function () {}
Vue.prototype.$destroy = function () {}
Vue原型上添加了_update
,$forceUpdate
,$destory
方法,方法内部针对同名周期做了组件的更新和状态的记录。
renderMixin
// 渲染相关的功能函数
installRenderHelpers(Vue.prototype)
Vue.prototype.$nextTick = function (fn: Function) {}
Vue.prototype._render = function (): VNode {}
此时的Vue
1. initMixin(Vue) --> src/core/instance/init.js
* Vue.prototype._init (day02)
2. stateMixin(Vue) --> src/core/instance/state.js
* Vue.prototype.$data
* Vue.prototype.$set = set
* Vue.prototype.$delete = del
* Vue.prototype.$watch
3. eventsMixin(Vue) --> src/core/instance/events.js
* Vue.prototype.$on
* Vue.prototype.$once
* Vue.prototype.$off
* Vue.prototype.$emit
4. lifecycleMixin(Vue) --> src/core/instance/lifecycle.js
* Vue.prototype._update
* Vue.prototype.$forceUpdate
* Vue.prototype.$destroy
5. renderMixin(Vue)
* Vue.prototype.$nextTick
* Vue.prototype._render
* Vue.prototype['一些辅助渲染相关的函数']
我们看下一个引用文件
四、src/core/index.js
initGlobalAPI(Vue)
Object.defineProperty(Vue.prototype, '$isServer', {
get: isServerRendering
})
Object.defineProperty(Vue.prototype, '$ssrContext', {
get () {
return this.$vnode && this.$vnode.ssrContext
}
})
Vue.version = '__VERSION__'
先看initGlobalAPI(Vue)
Object.defineProperty(Vue, 'config', configDef)
Vue.util = {
warn,
extend,
mergeOptions,
defineReactive
}
Vue.set = set
Vue.delete = del
Vue.nextTick = nextTick
/*
* options配置
* {
* components,
* directives,
* filters
* }
*/
Vue.options = Object.create(null)
ASSET_TYPES.forEach(type => {
Vue.options[type + 's'] = Object.create(null)
})
Vue.options._base = Vue
/*
* builtInComponents 为 KeepAlive
* 即为Vue配置全局keepAlive内置组件,应该还会在某个地方配Transtion
* 其他内置的指令、过滤器以后应该也会配进options里
*/
extend(Vue.options.components, builtInComponents)
// Vue.use = function () {} 使用插件的方法
initUse(Vue)
// Vue.mixin = function () {}
initMixin(Vue)
/*
* Vue.cid = 0
* Vue.extend = function () {} 应该是继承相关的
*/
initExtend(Vue)
/*
* Vue.component = function () {}
* Vue.directive = function () {}
* Vue.filter = function () {}
*/
initAssetRegisters(Vue)
然后
Vue.version = '__VERSION__'
Object.defineProperty(Vue.prototype, '$isServer', {
get: isServerRendering
})
Object.defineProperty(Vue.prototype, '$ssrContext', {
get () {
/* istanbul ignore next */
return this.$vnode && this.$vnode.ssrContext
}
})
我们按照import顺序继续看
五、src/platforms/web/runtime/index.js
此文件做了这些事情
// 安装平台指定utils
Vue.config.mustUseProp = mustUseProp
Vue.config.isReservedTag = isReservedTag
Vue.config.isReservedAttr = isReservedAttr
Vue.config.getTagNamespace = getTagNamespace
Vue.config.isUnknownElement = isUnknownElement
// 安装平台相关指令和组件
/*
* platformDirectives中是model,show, 内置的指令,那if等是在哪里加上的呢?
*
* platformComponents 中是Transition,TransitionGroup,前面提到的就是在这加* 上的
*/
extend(Vue.options.directives, platformDirectives)
extend(Vue.options.components, platformComponents)
// install platform patch function
Vue.prototype.__patch__ = inBrowser ? patch : noop
Vue.prototype.$mount = function () {}
然后看最后一个文件
六、src/platforms/web/entry-runtime-with-compiler.js
const mount = Vue.prototype.$mount
Vue.prototype.$mount = function () {
// xxx 针对template或el的情况做一些处理
return mount.call(this, el, hydrating)
}
// 在$mount 中有调用compileToFunctions,函数作用是template 编译为render函数
Vue.compile = compileToFunctions
结语
此章完,主要看了Vue的初始化的过程。