外观
接上回,我们确认了一个入口文件src/platforms/web/entry-runtime-with-compiler.js ,将该文件代码折叠如下图所示,方便一览全局:
可以看到这里import Vue from './runtime/index' 引入了一个Vue ,然后定义了下Vue.prototype.$mount 和Vue.compile ,看Vue源码之前最好是先过一下Vue的官方文档,这里Vue.prototype.$mount 是一个关在Vue原型链上的属性,所以通过new Vue() 创建的Vue的实例都会继承这个$mount 方法,在看这个方法的作用之前,因为看过了官方文档,并且我之前用了两年的Vue了,所以先猜测下这个大概跟Vue组件生命周期里的mounted 钩子可能有关系,可能是这个$mount 方法执行完后就会触发组件生命周期里的mounted 这个钩子里写的程序。现在详细看下相关代码:
const mount = Vue.prototype.$mount;
// 返回类型是Component,这个类型下文具体讲,就直译为返回一个组件即可
Vue.prototype.$mount = function (
// el是可选参数,值是字符串(css选择符)或dom元素(Element)
el?: string | Element,
// hydrating也是可选参数,布尔类型,以前用过redux-persist这个库,那里这种名词的意思是是否恢复之前的数据
hydrating?: boolean,
): Component {
// 如果el是元素则值维持不变,如果el是字符串则赋值为通过document.querySelector(el)匹配到的元素
el = el && query(el);
// 下面注释里的istanbul指的是一个叫istanbul的代码覆盖率工具
/* istanbul ignore if */
if (el === document.body || el === document.documentElement) {
process.env.NODE_ENV !== "production" &&
warn(
// 如果元素是body/document.documentElement,且非针对生产环境打包的话,则提示用户不要将Vue绑定到html或body元素上
`Do not mount Vue to <html> or <body> - mount to normal elements instead.`,
);
// 返回this
return this;
}
// 一个$options属性
const options = this.$options;
// 如果没有定义render函数,则Vue会按下面这样去定义一个render函数
// resolve template/el and convert to render function
if (!options.render) {
let template = options.template;
if (template) {
// 如果有模版
if (typeof template === "string") {
if (template.charAt(0) === "#") {
// 如果template是一个id选择器(以#开头),则将template重新赋值为对应元素的innerHTML
template = idToTemplate(template);
/* istanbul ignore if */
if (process.env.NODE_ENV !== "production" && !template) {
// 如果id关联到的innerHTML为空或不存在,则在非生产版本下提示用户
warn(
`Template element not found or is empty: ${options.template}`,
this,
);
}
}
} else if (template.nodeType) {
// 如果template不是字符串,但是有nodeType属性,则判断template为dom,取其innerHTML作为模版
template = template.innerHTML;
} else {
if (process.env.NODE_ENV !== "production") {
warn("invalid template option:" + template, this);
}
// 返回this
return this;
}
} else if (el) {
// 如果没有模板但是有元素,就取元素的outerHtml或近似等价的东西
template = getOuterHTML(el);
}
if (template) {
/* istanbul ignore if */
if (process.env.NODE_ENV !== "production" && config.performance && mark) {
// 通过window.performance.mark来标记性能监测点'compile'
mark("compile");
}
// 获得render和staticRenderFns函数,并挂到Vue.property.$options对象上
const { render, staticRenderFns } = compileToFunctions(
template,
{
shouldDecodeNewlines,
shouldDecodeNewlinesForHref,
delimiters: options.delimiters,
comments: options.comments,
},
this,
);
options.render = render;
options.staticRenderFns = staticRenderFns;
/* istanbul ignore if */
if (process.env.NODE_ENV !== "production" && config.performance && mark) {
// 通过window.performance.mark标记性能监测点'compile end'
mark("compile end");
// 通过window.erformance.measure来测量compile和compile end这两个性能监测点间的用时
measure(`vue ${this._name} compile`, "compile", "compile end");
}
}
}
// 再次调用mount方法
return mount.call(this, el, hydrating);
};好了,这篇文章对入口文件的分析就写到这里,后续我们将以入口文件为线索展开阅读其他部分的代码。打算看一下Vue.compile = compileToFunctions 这里的compileToFunctions 方法,以及import Vue from './runtime/index' 这里导入的Vue 。