text: /* @flow */
  
  import config from 'core/config'
  import { warn, cached } from 'core/util/index'
  import { mark, measure } from 'core/util/perf'
  
  import Vue from './runtime/index'
  import { query } from './util/index'
  import { compileToFunctions } from './compiler/index'
  import {
    shouldDecodeNewlines,
    shouldDecodeNewlinesForHref
  } from './util/compat'
  
  const idToTemplate = cached(id => {
    const el = query(id)
    return el && el.innerHTML
  })
  
  const mount = Vue.prototype.$mount // 缓存了原型上的$mount方法，然后基于compiler版本做了相应修改；原始$mount方法是在./runtime/index.js中定义的
  Vue.prototype.$mount = function(
    el?: string | Element,
    hydrating?: boolean
  ): Component {
    el = el && query(el) // query返回一个dom元素
  
    // el 不能是body、html元素(因为挂载会替换对应元素)
    /* istanbul ignore if */
    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
    }
  
    const options = this.$options
    // resolve template/el and convert to render function
    // options上没有render，则需要生成render函数
    if (!options.render) {
      // 获取template
      let template = options.template
      if (template) {
        if (typeof template === 'string') {
          if (template.charAt(0) === '#') {
            // template是一个id选择器，则取其innerHTML
            template = idToTemplate(template)
            /* istanbul ignore if */
            if (process.env.NODE_ENV !== 'production' && !template) {
              warn(
                `Template element not found or is empty: ${options.template}`,
                this
              )
            }
          }
        } else if (template.nodeType) {
          // template传入的是一个dom对象,取其innerHTML
          template = template.innerHTML
        } else {
          if (process.env.NODE_ENV !== 'production') {
            warn('invalid template option:' + template, this)
          }
          return this
        }
      } else if (el) {
        // 未指定template字段，但el存在，则获取el的outerHTML(innerHTML+el标签自身)
        template = getOuterHTML(el)
      }
  
      // 将获取到template编译成函数，保存到options上
      if (template) {
        /* istanbul ignore if */
        if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
          mark('compile')
        }
  
        // 编译，生成render函数
        const { render, staticRenderFns } = compileToFunctions(
          template,
          {
            shouldDecodeNewlines,
            shouldDecodeNewlinesForHref,
            delimiters: options.delimiters,
            comments: options.comments
          },
          this
        )
  
        // 赋值到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')
        }
      }
    }
  
    // 调用缓存的公共$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.compile = compileToFunctions
  
  export default Vue
  