源码调试采坑记录:vue源码下载下来,出现如下错误。
Error: Could not load C:\vue\src\core/config (imported by C:\vue\src\platforms\web\entry-runtime-with-compiler.js): ENOENT: no such file
or directory, open 'C:\vue\src\core\config'
vue使用rollup打包,rollup路径在windows下会出错,解决办法:
rollup-plugin-alias插件中路径'/'应该改为'',将node_modules/rollup-plugin-alias/dist/rollup-plugin-alias.js 第70行:
const entry = options[toReplace]; 改为 const entry = normalizeId(options[toReplace]);
打开package.json

TARGET=web-full-dev
去scripts\config.js找"web-full-dev”

入口文件:src\platforms\web\entry-runtime-with-compiler.js
// 扩展$mount
const mount = Vue.prototype.$mount
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
el = el && query(el)
}
// 获取选项
const options = this.$options
// 若不存在render选项则将template/el的设置转换为render函数
if (!options.render) {
let template = options.template
if (template) {
// 解析template选项
} else if (el) {
// 否则解析el选项
template = getOuterHTML(el)
}
}
if (template) {
// 编译得到render函数
const { render, staticRenderFns } = compileToFunctions(template, {..}, this)
options.render = render
}

跟着import进到src\platforms\web\runtime\index.js
// 定义组件实例补丁方法
Vue.prototype.__patch__ = inBrowser ? patch : noop
//实现$mount
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
el = el && inBrowser ? query(el) : undefined
// $mount挂载时执行mountComponent(挂载组件)
return mountComponent(this, el, hydrating)
}
- mountComponent执行首次渲染、更新 (src\core\instance\lifecycle.js)
export function mountComponent (
vm: Component,
el: ?Element,
hydrating?: boolean
): Component {
//获取根元素
vm.$el = el
//调用beforeMount钩子函数
callHook(vm, 'beforeMount')
//创建组件更新函数
const updateComponent = () => {
vm._update(vm._render(), hydrating)
}
//创建组件实例对应的watcher
new Watcher(vm, updateComponent, noop, {
before () {
if (vm._isMounted && !vm._isDestroyed) {
callHook(vm, 'beforeUpdate')
}
}
}, true /* isRenderWatcher */)
//$vode不存在
if (vm.$vnode == null) {
vm._isMounted = true
//调用mounted钩子函数
callHook(vm, 'mounted')
}
return vm
}

接着进到src\core\index.js 这里定义了全局API
import Vue from './instance/index'
import { initGlobalAPI } from './global-api/index'
// 初始化全局api:Vue.set/delete/nextTick等
initGlobalAPI(Vue)
export default Vue
- initGlobalAPI(Vue)全局API实现(src\core\global-api\index.js)
export function initGlobalAPI (Vue: GlobalAPI) {
Vue.set = set
Vue.delete = del
Vue.nextTick = nextTick
initUse(Vue) // 实现Vue.use函数
initMixin(Vue) // 实现Vue.mixin函数
initExtend(Vue) // 实现Vue.extend函数
initAssetRegisters(Vue) // 注册实现Vue.component/directive/filter
}

最后找到Vue构造函数 src\core\instance\index.js
function Vue (options) {
// 构造函数仅执行了_init
this._init(options)
}
// 实现init函数
initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
export default Vue
- initMixin(Vue) 实现_init src\core\instance\init.js
export function initMixin (Vue: Class<Component>) {
Vue.prototype._init = function (options?: Object) {
const vm: Component = this
initLifecycle(vm) // 设置$parent,$root,$children等组件关系属性
initEvents(vm) // 监听附加在组件上的事件
initRender(vm) // 初始化组件插槽、声明createElement方法
callHook(vm, 'beforeCreate') // 调用beforeCreate钩子
initInjections(vm)// 初始化注入数据
initState(vm) // 初始化组件data,methods,computed,watch
initProvide(vm) // 为后代提供数据
callHook(vm, 'created') // 调用created钩子
// 如果new的时候有el,就直接调用$mount
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
}
}
- stateMixin(Vue) 定义了
props,
delete,$watch
src\core\instance\state.js
export function stateMixin (Vue: Class<Component>) {
// 定义只读属性$data和$props
const dataDef = {}
dataDef.get = function () { return this._data }
const propsDef = {}
propsDef.get = function () { return this._props }
Object.defineProperty(Vue.prototype, '$data', dataDef)
Object.defineProperty(Vue.prototype, '$props', propsDef)
// 定义$set和$delete
Vue.prototype.$set = set
Vue.prototype.$delete = del
// 定义$watch
Vue.prototype.$watch = function (): Function {...}
}
- eventsMixin(Vue)定义了
emit,
once
src\core\instance\events.js
export function eventsMixin (Vue: Class<Component>) {
Vue.prototype.$on = function (event: string | Array<string>, fn: Function):Component {}
Vue.prototype.$once = function (event: string, fn: Function): Component {}
Vue.prototype.$off = function (event?: string|Array<string>, fn?:Function):Component {}
Vue.prototype.$emit = function (event: string): Component {}
}
- lifecycleMixin(Vue)定义了_update,
destroy
src\core\instance\lifecycle.js
export function lifecycleMixin (Vue: Class<Component>) {
Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {}
Vue.prototype.$forceUpdate = function () {}
Vue.prototype.$destroy = function () {}
}
- renderMixin(Vue)定义两个实例方法$nextTick和_render
src\core\instance\render.js
export function renderMixin (Vue: Class<Component>) {
Vue.prototype.$nextTick = function (fn: Function) {
return nextTick(fn, this)
}
Vue.prototype._render = function (): VNode {}
}