Vue2.0 version

Note: we are not talking about the release version of Vue, but the packaged and compiled version of Vue. We all know that Vue 2+ is packaged using rollup, and Vue is divided into:

  • Entry-run-time with-compiler Specifies the version that can compile the template
  • Only the runtime version is Entry-Runtime

Why the runtime version

Entry-run-time with-compiler internally overrides the mount function $mount because the Compiler version handles the template field separately for Vueoptions. The template field should be compiled separately with the Vue Compiler. We usually don’t use the template option to write template inside a single file, so we just use the runtime version

Exposed Vue functions

Look from the source Vue is itself a function, it in Vue/SRC/core/instance/index. Js directory

// code

function Vue(options) {
  if(process.env.NODE_ENV ! = ='production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')}this._init(options)
}

// code
export default Vue
Copy the code

Once you have defined the Vue constructor (that is, the class in ES5), mix in:

  • Initialize the
  • State with
  • Event with
  • Life cycle mixing
  • Render function blending

Import the Vue

After importing the Vue, JS creates the runtime of the Vue:

  • Define a constructor Vue (class)
  • Create the total Vue runtime

Runtime: initMixin

Create Vue. Prototype. _init method. This method will run after Vue is instantiated. Outside of Vue is the instance created by new Vue. This is a typical object-oriented programming idea.

$on(event, fn);

InitEvents are important for initialization of: listeners, where there is no $on on the instance yet, but it does not affect execution because these times are not triggered.

You can see how the $Listeners API is used here.

Runtime: initRender

On the VM instance:

  • _vnode
  • _staticTrees
  • $slots
  • $scopedSlots
  • _c
  • $createElement

The important point is to create the above VM instance methods and attributes, where $createElement is the created element and component, and its return value is the created VNode node. All we touch are vNodes

Run time: callHook, beforeCreate

Vm. _hasHookEvent = false, vm.$emit is not defined, this will obviously not fire

PushTarget () does not pass in target, but instead adds the Class target attribute

Runtime: initInjections

Handle inject option of defineReactive

Runtime: initState

  • initProps
  • initMethods
  • initData/ observe(data ={})
  • initComputed
  • initWatch

$mount

Mount function Vue. Prototype. $mount at/[email protected] / SRC/platforms/web/runtime/index, js is defined

/* @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 utilsVue.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((a)= > {
    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 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)}export default Vue
Copy the code
  • mountedComponent
export function mountComponent (vm: Component, el: ? Element, hydrating? : boolean) :Component {
  vm.$el = el
  if(! vm.$options.render) { vm.$options.render = createEmptyVNode// coes
  }
  callHook(vm, 'beforeMount')

  let updateComponent
  /* istanbul ignore if */
  if(process.env.NODE_ENV ! = ='production' && config.performance && mark) {
    // codes
  } else {
    updateComponent = (a)= > {
      vm._update(vm._render(), hydrating)
    }
  }

  // we set this to vm._watcher inside the watcher's constructor
  // since the watcher's initial patch may call $forceUpdate (e.g. inside child
  // component's mounted hook), which relies on vm._watcher being already defined
  new Watcher(vm, updateComponent, noop, {
    before () {
      if(vm._isMounted && ! vm._isDestroyed) { callHook(vm,'beforeUpdate')}}},true /* isRenderWatcher */)
  hydrating = false

  // manually mounted instance, call mounted on self
  // mounted is called for render-created child components in its inserted hook
  if (vm.$vnode == null) {
    vm._isMounted = true
    callHook(vm, 'mounted')}return vm
}
Copy the code
  • _update
Vue.prototype._update = function (vnode: VNode, hydrating? : boolean) {
    const vm: Component = this
    const prevEl = vm.$el
    const prevVnode = vm._vnode
    const restoreActiveInstance = setActiveInstance(vm)
    vm._vnode = vnode
    // Vue.prototype.__patch__ is injected in entry points
    // based on the rendering backend used.
    if(! prevVnode) {// initial render
      vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */)}else {
      // updates
      vm.$el = vm.__patch__(prevVnode, vnode)
    }
    restoreActiveInstance()
    // update __vue__ reference
    if (prevEl) {
      prevEl.__vue__ = null
    }
    if (vm.$el) {
      vm.$el.__vue__ = vm
    }
    // if parent is an HOC, update its $el as well
    if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) {
      vm.$parent.$el = vm.$el
    }
    // updated hook is called by the scheduler to ensure that children are
    // updated in a parent's updated hook.
  }
Copy the code

The __Patch__ method is essentially called

Vue.prototype.__patch__ = inBrowser ? patch : noop

// path
export const patch: Function = createPatchFunction({ nodeOps, modules })
Copy the code
  • CreatePatchFunction returns a patch function. CreatePatchFunction itself is an extremely complex function designed into the virtual DOM,diff algorithm, and so on.