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

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

这个文件是导出web平台带编译模板的入口,我们先看这个文件都做了哪些工作。

// 导入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。

// 引入核心的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

复制代码

转载于:https://juejin.im/post/5ccd962be51d453a572aa2b1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值