vue解析系列(一):runtime-with-compiler&runtime vue

runtime-with-compilergithub.com/vuejs/vue/b…

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

runtime vue github.com/vuejs/vue/b…

此文件導出運行時的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

複製代碼
相關文章
相關標籤/搜索