这个文件是导出web平台带编译模板的入口,咱们先看这个文件都作了哪些工做。javascript
// 导入vue的一些配置选项
import config from 'core/config'
// 导入warn和cached函数
import {
warn,
cached
} from 'core/util/index'
// 性能统计的函数
import {
mark,
measure
} from 'core/util/perf'
// 运行时的vue,就是咱们平时webpack打包后在线上运行,去除模板编译函数的。
import Vue from './runtime/index'
// query函数,用来查询挂载的dom节点
import {
query
} from './util/index'
// 将模板编译成函数
import {
compileToFunctions
} from './compiler/index'
// 编译模板相关
import {
shouldDecodeNewlines,
shouldDecodeNewlinesForHref
} from './util/compat'
// 使这个查询innerHtml的纯函数具备缓存的功能
// 好比两次调用idToTemplate('a'), 第二次直接返回结果, 不会再去执行query。
const idToTemplate = cached(id => {
const el = query(id)
return el && el.innerHTML
})
// 缓存原始的Vue.prototype.$mount函数
const mount = Vue.prototype.$mount
// 从新设置Vue.prototype.$mount
// 主要是将template编译为render函数
Vue.prototype.$mount = function ( el ?: string | Element, // vue挂载的元素 hydrating ?: boolean // 服务端相关, 暂时不去理解。 ): Component {
// 查询真实的dom节点
el = el && query(el)
// el若是是body或者document,在非生产环境warn,以后return当前instance、
// 因此咱们不能将vue挂载到dody或者document上, 主要是vue会把挂载的节点替换掉
if (el === document.body || el === document.documentElement) {
process.env.NODE_ENV !== 'production' && warn(
`Do not mount Vue to <html> or <body> - mount to normal elements instead.`
)
return this
}
// 这个options是vue默认的options和咱们传入options合并以后的。
// 合并发生在vue的init函数里。
const options = this.$options
// 若是没有render函数,使用template的写法
if (!options.render) {
let template = options.template
// 对template的多种状况进行不一样的处理
// 咱们日常写template都不在在里面的逻辑进行处理
if (template) {
if (typeof template === 'string') {
// 若是template是以#开始, vue认为只是一个id,会去查找真实节点的innerHtml做为模板
if (template.charAt(0) === '#') {
template = idToTemplate(template)
// 若是没有会在开发环境提示用户
if (process.env.NODE_ENV !== 'production' && !template) {
warn(
`Template element not found or is empty: ${options.template}`,
this
)
}
}
} else if (template.nodeType) {
// 若是是真实dom, 直接取innerHtml
template = template.innerHTML
} else {
if (process.env.NODE_ENV !== 'production') {
warn('invalid template option:' + template, this)
}
return this
}
} else if (el) {
// 获取outerHmlt做为template
template = getOuterHTML(el)
}
if (template) {
// 性能统计
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
mark('compile')
}
// 将template转化为render函数,
// 咱们的线上环境都是在webpack打包过程当中转化template为render函数了。
// 咱们直接写render函数是否是build会快些?🤣
// 具体是如何编译咱们暂时不去了解,咱们目前分析render函数的。
const {
render,
staticRenderFns
} = compileToFunctions(template, {
shouldDecodeNewlines, // 对不一样浏览器作兼容
shouldDecodeNewlinesForHref, // 对不一样浏览器作兼容
delimiters: options.delimiters, // ref: https://cn.vuejs.org/v2/api/#delimiters
comments: options.comments // ref: https://cn.vuejs.org/v2/api/#comments
}, this)
// 将render函数和staticRenderFns放到实例的options上
options.render = render
options.staticRenderFns = staticRenderFns
/* istanbul ignore if */
// 性能统计结束
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
mark('compile end')
measure(`vue ${this._name} compile`, 'compile', 'compile end')
}
}
}
// 执行runTime的vue实例的mount函数
return mount.call(this, el, hydrating)
}
/** * Get outerHTML of elements, taking care * of SVG elements in IE as well. */
function getOuterHTML (el: Element): string {
if (el.outerHTML) {
return el.outerHTML
} else {
const container = document.createElement('div')
container.appendChild(el.cloneNode(true))
return container.innerHTML
}
}
// 编译函数挂载到vue上, 估计是供外部工具调用
// 猜想vue-loader使用了这个
Vue.compile = compileToFunctions
// 导出vue
export default Vue
复制代码
此文件导出运行时的vue,就是能够处理render函数,可是不能处理tmeplate的vue,也就是runtime-with-compiler引入的vue。html
// 引入核心的vue
import Vue from 'core/index'
// 引入相关配置
import config from 'core/config'
// 引入工具函数
import { extend, noop } from 'shared/util'
// 引入mountComponent函数
import { mountComponent } from 'core/instance/lifecycle'
// 引入工具函数
import { devtools, inBrowser, isChrome } from 'core/util/index'
// 引入web平台工具函数
import {
query, // 查询节点
mustUseProp, // 判断属性是否是必须绑定
isReservedTag, // 是不是保留tag
isReservedAttr, // 是否为保留属性
getTagNamespace, // 获取tag的namespace
isUnknownElement // 是不是未知的element
} from 'web/util/index'
// 引入用来对比虚拟node的patch函数
import { patch } from './patch'
// 引入平台相关的指令 {model, show}
import platformDirectives from './directives/index'
// 引入平台相关组件 {Transition, TransitionGroup}
import platformComponents from './components/index'
// 在vue.config添加各类工具函数
Vue.config.mustUseProp = mustUseProp
Vue.config.isReservedTag = isReservedTag
Vue.config.isReservedAttr = isReservedAttr
Vue.config.getTagNamespace = getTagNamespace
Vue.config.isUnknownElement = isUnknownElement
// install platform runtime directives & components
// 在vue.options上添加平台相关指令和组件
extend(Vue.options.directives, platformDirectives)
extend(Vue.options.components, platformComponents)
// 若是不是在浏览器的环境下vue原型上的patch函数为空
Vue.prototype.__patch__ = inBrowser ? patch : noop
// public mount method
// 添加runtime mount函数
Vue.prototype.$mount = function ( el?: string | Element, // 节点 hydrating?: boolean // 服务端相关 ): Component {
el = el && inBrowser ? query(el) : undefined
// 执行mountComponent函数并返回
return mountComponent(this, el, hydrating)
}
// devtools global hook
/* istanbul ignore next */
// 开发工具
if (inBrowser) {
setTimeout(() => {
if (config.devtools) {
if (devtools) {
devtools.emit('init', Vue)
} else if (
process.env.NODE_ENV !== 'production' &&
process.env.NODE_ENV !== 'test' &&
isChrome
) {
console[console.info ? 'info' : 'log'](
'Download the Vue Devtools extension for a better development experience:\n' +
'https://github.com/vuejs/vue-devtools'
)
}
}
if (process.env.NODE_ENV !== 'production' &&
process.env.NODE_ENV !== 'test' &&
config.productionTip !== false &&
typeof console !== 'undefined'
) {
console[console.info ? 'info' : 'log'](
`You are running Vue in development mode.\n` +
`Make sure to turn on production mode when deploying for production.\n` +
`See more tips at https://vuejs.org/guide/deployment.html`
)
}
}, 0)
}
// 导出vue
export default Vue
复制代码