這個文件是導出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
複製代碼