Vue2.6, ask me why don’t I see 3? At least I have to understand 2 first, I think 2 is still very classic, although the combined API of Vue3 is highly respected, but I still used to write declarative in Vue3, really a personal habit (I will change slowly, mainly because I have no project to do now!). In terms of performance, small projects should not have much impact. One is to read the source code for the future interview can blow, there is to learn from the excellent code, understand his organizational structure, and finally can give their own use of the pit.

0.import Vue

When it comes to new Vue(), first you have to have Vue, go to demo first

import Vue form 'Vue'
new Vue()
Copy the code

There are two processes, one is constructor introduction (or class introduction), and the second is actually creating an instance of vUE. Light is introduced into the Vue constructor, which has already done a lot of work, mainly to add static properties and properties on the prototype chain to the Vue, which would look something like this if represented in ES6 class

export class Vue {
    
    constructor(options){
        this._init(options)
    }
    
    // Static properties and methods
    static key
    static foo1(){}...// Stereotype attributes and methods
    public key2
    public foo2(){}... ._init(){}}Copy the code

This is basically true for ES5

// Prototype attributes
Vue.prototype.key = 
// Static attributes
Vue.key2 =
// constructor
function Vue(options){
    this._init(options)
}
Copy the code

1. Create the Vue class

1.1 Vue entrance

platforms/web/entry-runtime.js

import Vue from './runtime/index'
export default Vue
Copy the code

1.2 Runtime files

platform/web/runtime/index.js

Vue.config.mustUseProp = mustUseProp Vue.config.isReservedTag = isReservedTag Vue.config.isReservedAttr = isReservedAttr  Vue.config.getTagNamespace = getTagNamespace Vue.config.isUnknownElement = isUnknownElement// Register the built-in directive v-model v-show
extend(Vue.options.directives, platformDirectives)
// Transition, TransitionGroup
extend(Vue.options.components, platformComponents)

Vue.prototype.__patch__ = inBrowser ? patch : noop

Vue.prototype.$mount = function(){}
Copy the code

1.3 Kernel Files

core/index.js

import Vue from './instance/index'
import { initGlobalAPI } from './global-api/index'
import { isServerRendering } from 'core/util/env'
import { FunctionalRenderContext } from 'core/vdom/create-functional-component'

Vue static properties and methods are on the class, not on the instance
initGlobalAPI(Vue)

// SSR correlation can be ignored
Object.defineProperty(Vue.prototype, '$isServer', {
  get: isServerRendering
})

Object.defineProperty(Vue.prototype, '$ssrContext', {
  get () {
    /* istanbul ignore next */
    return this.$vnode && this.$vnode.ssrContext
  }
})

// expose FunctionalRenderContext for ssr runtime helper installation
Object.defineProperty(Vue, 'FunctionalRenderContext', {
  value: FunctionalRenderContext
})

Vue.version = '__VERSION__'
Copy the code

InitGlobalAPI in core/global-api/index.js mounts static properties and methods on some Vue classes

export function initGlobalAPI (Vue: GlobalAPI) {

  Object.defineProperty(Vue, 'config', configDef)
  
  Vue.util = {
    warn,
    extend,
    mergeOptions,
    defineReactive
  }

  Vue.set = set
  Vue.delete = del
  Vue.nextTick = nextTick
  
  Vue.observable = <>(obj: T): T => { observe(obj) return obj } // ... // The keep-alive component extends (Vue.options.components, Vue.options.components, Vue.options.components, Vue.options.components, Vue.options.components, builtInComponents) // Vue.use initUse(Vue) // Vue.mixin initMixin(Vue) // Vue.extend initExtend(Vue) // Vue.components, Vue.directive, Vue.filter initAssetRegisters(Vue) }Copy the code

1.4 Vue constructor Definitions (Instance file)

core/instance/index.js

function Vue(options){
    // Only new cannot be executed directly
    // ...
    this._init(options)
}

// Add something to the Vue prototype chain

/** * instance creation API (used for internal creation) * _init */
initMixin(Vue)
$data * $props * $set * $delete * $watch */
stateMixin(Vue)
$on * $once * $off * $emit */
eventsMixin(Vue)
/** * add attribute * _update * $forceUpdate * $destroy */ to Vue prototype chain
lifecycleMixin(Vue)
$nextTick * _render helpers = $nextTick * _render helpers */
renderMixin(Vue)
Copy the code

To summarize, the properties that existed before the Vue class was created

// ------- static properties and methods ------------------
// The default options attribute is merged with the incoming and outgoing parameters
Vue.options = {
  components: {
    KeepAlive: {}
    Transition: {}
    TransitionGroup: {}},directives: {
    model: {inserted: ƒ.componentUpdated: ƒ}
    show: {bind: ƒ.update: ƒ.unbind: ƒ}},filters: {}
  _base
}

Vue.verison
Vue.FunctionalRenderContext

Vue.config.mustUseProp
Vue.config.isReservedTag 
Vue.config.isReservedAttr
Vue.config.getTagNamespace
Vue.config.isUnknownElement

Vue.use
Vue.mixin
Vue.extend
Vue.components
Vue.directive
Vue.filter

// ------- Instance properties and methods ------------------
Vue.prototype.$isServer
Vue.prototype.$ssrContext

Vue.prototype.__patch__ 
Vue.prototype.$mount

// Data is relevant
Vue.prototype.$data
Vue.prototype.props
Vue.prototype.$set
Vue.prototype.$delete
Vue.prototype.$watch

// Event related
Vue.prototype.$on
Vue.prototype.$once
Vue.prototype.$once
Vue.prototype.$emit

// Render related
Vue.prototype._update
Vue.prototype.$forceUpdate
Vue.prototype.$destory

// Lifecycle correlation
// A bunch of renderer functions are mounted
installRenderHelpers()
Vue.prototype.$nextTick
Vue.prototype._render


Copy the code

2. Create a Vue instance_init

 // Vue's real constructor
  Vue.prototype._init = function (options? :Object) {
    const vm: Component = this

    // Global vue instance 🆔
    vm._uid = uid++
    
    // ...

    // a flag to avoid this being observed
    vm._isVue = true
    // merge options
    if (options && options._isComponent) {
      initInternalComponent(vm, options)
    } else {
      // All self-developed components go to this point, merging the options properties generated by Vue before mounting them to $options
      vm.$options = mergeOptions(
        // This function will find the options property up the inheritance chain
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      )
    }

    // The agent should optimize the performance of the render function in the development environment, and the agent should optimize its performance in the production environment
    if(process.env.NODE_ENV ! = ='production') {
      initProxy(vm)
    } else {
      vm._renderProxy = vm
    }
    
    // expose real self
    vm._self = vm
    // Initialize instance parameters
    // Lifecycle
    initLifecycle(vm)
    / / event
    initEvents(vm)
    / / rendering
    initRender(vm)
    // Execute the instance to create the front hook
    callHook(vm, 'beforeCreate')
    
    initInjections(vm) // resolve injections before data/props
    initState(vm)
    initProvide(vm) // resolve provide after data/props

    // Execute the instance to create the hook
    callHook(vm, 'created')

    / /...

    // Mount to the real Dom
    New Vue({}).$mount("#app")
    if (vm.$options.el) {
      vm.$mount(vm.$options.el)
    }
  }
Copy the code

The following may be the specific operation of each attribute when reading the instance initialization in succession, hope the big guys more correct, to be continued…