从源码角度了解vue执行流程(一)

作为一个vuer终于开始对vue源码动手了,激动的心颤抖的手,不如撸行代码走一走。源码基于最新的v2.6.12版本开始叙述,可能会理解错误导致出入,还请指正,另外只做流程梳理,具体源码不做深入讲解,后续计划会出详细博文。

流程图

文章字数过多,太过繁琐,因此后期补了一张流程图
在这里插入图片描述

使用vue-cli脚手架创建简单的vue项目

项目目录建立如下图
项目目录-w150
当然少不得从入口文件开始

import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";

Vue.config.productionTip = false;

new Vue({
   
  router,
  store,
  render: h => h(App)
}).$mount("#app");

import Vue from “vue”;

不得不说一下vVue的两种模版编译方式,运行时+模版编译 vs 运行时,这两种区别就在于对于template的解析,即

new Vue({
   
  template: '<p>Vue</p>'
})

而借助于vue-loader工具,写在组件模版里面的代码会在构建时被预编译成javascript,而只包含运行时的版本会比运行时+模版编译轻量30%,所以尽可能地使用只包含运行时的版本,更多点击这里

当然我们这个博文是使用运行时+模版编译这种编译方式为例进行剖析。

当执行这句代码时,Vue源码内部会从入口文件开始,入口文件是src/platforms/web/webentry-runtime-with-compiler.js,也就是这段代码。

/* @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
Vue.prototype.$mount = function (
  el?: string | Element,
  hydrating?: boolean
): Component {
   
  el = el && query(el)

  /* 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
  if (!options.render) {
   
    let template = options.template
    if (template) {
   
      if (typeof template === 'string') {
   
        if (template.charAt(0) === '#') {
   
          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 = template.innerHTML
      } else {
   
        if (process.env.NODE_ENV !== 'production') {
   
          warn('invalid template option:' + template, this)
        }
        return this
      }
    } else if (el) {
   
      template = getOuterHTML(el)
    }
    if (template) {
   
      /* istanbul ignore if */
      if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
   
        mark('compile')
      }
      console.log('编译render')
      const {
    render, staticRenderFns } = compileToFunctions(template, {
   
        outputSourceRange: process.env.NODE_ENV !== 'production',
        shouldDecodeNewlines,
        shouldDecodeNewlinesForHref,
        delimiters: options.delimiters,
        comments: options.comments
      }, this)
      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')
      }
    }
  }
  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

执行该文件,当执行到import Vue from './runtime/index时,又开始执行src/platforms/web/runtime/index.js这个文件。

/* @flow */

import Vue from 'core/index'
import config from 'core/config'
import {
    extend, noop } from 'shared/util'
import {
    mountComponent } from 'core/instance/lifecycle'
import {
    devtools, inBrowser } from 'core/util/index'

import {
   
  query,
  mustUseProp,
  isReservedTag,
  isReservedAttr,
  getTagNamespace,
  isUnknownElement
} from 'web/util/index'

import {
    patch } from './patch'
import platformDirectives from './directives/index'
import platformComponents from './components/index'

// install platform specific utils
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
extend(Vue.options.directives, platformDirectives)
extend(Vue.options.components, platformComponents)

// install platform patch function
Vue.prototype.__patch__ = inBrowser ? patch : noop

// public mount method
Vue.prototype.$mount = function (
  el?: string | Element,
  hydrating?: boolean
): Component {
   
  el = el && inBrowser ? query(el) : undefined
  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'
      ) {
   
        console[console.info ? 'info' : 'log'](
          'Download the Vue Devtools extension for a better develo
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值