接上回,我们确认了一个入口文件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 。