The statement

🔊 This article is the second note for getting started with the Vue source code, currently version 2.6.14. If you have a little help, please like to encourage, if there are mistakes or omissions, please point out in the comments section, thank you very much.

🔊 code is basically annotated line by line, due to my limited ability, a lot of basic knowledge is also annotated and explained. Because the source code is too long, the article will not post the complete code, so basically are posted part of the pseudo-code and then analyzed.

🔊 from the beginning of this article, may appear temporarily do not understand the place, because has not learned the pre-knowledge, do not panic, just know that there is such a knowledge point, then look down, see the pre-knowledge, look back to see here at a glance.

Initialize the

The constructor

Vue is a constructor in nature. When we new vue, we must pass its constructor, so we first find its directory \vue-dev\ SRC \core\instance\index.js.

\vue-dev\src\core\instance\index.js

/* * @author: * @description: Vue is actually a class implemented with Function, we can only instantiate it with new Vue. * @Date: 2021-07-07 17:46:27 * @LastEditTime: 2021-07-09 19:08:26 * @FilePath: \vue-dev\src\core\instance\index.js */
 
 // The Vue constructor can only be initialized with the new keyword, and then the this._init method is called
function Vue (options) {
  if(process.env.NODE_ENV ! = ='production' &&
    The instanceof operator is used to check whether the constructor's prototype property appears on the prototype chain of an instance object.
    // Vue must be a new instantiation of the es5 implementation of class (via functions)! (this instanceof Vue)
  ) {
    // If not Vue instance go here
    warn('Vue is a constructor and should be called with the `new` keyword')}// vue.prototype. _init Method This method is defined in initMixin, and its input parameter options is the object we passed in when we defined the object
  this._init(options)
}
 
/** * Execute the xxxMixin method to initialize the related function definition. This is just to define the function, which will be used later. * Each Mixin is to add some properties or methods to the Vue prototype */ 
 
// Merge the configuration
initMixin(Vue)
//stateMixin defines $data, $props, $set, $delete, $watch, and $data, $props is read-only.
stateMixin(Vue)
// Initialize the event center
eventsMixin(Vue)
// Initialize the lifecycle by calling the declaration cycle hook function
lifecycleMixin(Vue)
// Initialize render
renderMixin(Vue)
 
Copy the code

Code reading

⭐ Vue is actually a class implemented with Function, and we can only instantiate it with new Vue and then call this._init.

⭐ why is Vue not implemented using ES6 classes? As you can see below the constructor, many xxxMixin function calls are made, passing in Vue as arguments. Their function is to extend some methods on Vue’s prototype. Vue implements these extensions in multiple modules by function, rather than implementing all of them in one module. This approach is difficult to implement with Class. The advantage of doing this is that it is very easy to maintain and manage the code, and the programming skills are well worth learning.

Let’s conclude with a mind map

The process of the init

Let’s take a look at what happens to this._init(options). The _init method is added to the prototype of Vue in initMixin.

\vue-dev\src\core\instance\init.js

initMixin / _init

/ * * *@description: Define vue.prototype. _init method *@param {*} Vue Vue constructor */
export function initMixin (Vue: Class<Component>) {

  /** * Mount a _init method on the prototype of the Vue */ responsible for the Vue initialization process */
  Vue.prototype._init = function (options? :Object) {

/ / ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` part I ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `
    // Get the vue instance
    const vm: Component = this
    // Each vue instance has a _uid, which is incremented to ensure uniqueness
    vm._uid = uid++ 
    // Vue instances should not be reactive, make a mark
    vm._isVue = true

/ / ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` second part ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `

    $options, vue will put all related properties and methods into the vm.$options to prepare for subsequent calls. The attributes for Vue.$option come from two aspects, one predefined by Vue's vm.constructor and the other from the input object */ passed in when new Vue
    if (options && options._isComponent) {
    /** * If the subcomponent initializes here, only some performance optimizations have been made ** To put some deep properties on the component configuration object in the vm.$options option to improve the code execution efficiency */
      initInternalComponent(vm, options)
    } else {
      /** * Merge configuration items * If root component initialization goes here, merge Vue global configuration to root component local configuration, For example, Vue.com Ponent's registered global components are merged into the components option of the root instance * For each child component, the merge occurs in two places: * 2, {components: Local components registered in {xx}} have options merged when executing the compiler generated render function, including the components configuration (compiler) */ in the root component
      vm.$options = mergeOptions(
        // This is the default configuration of the component directive filter, i.e. Options in the constructor
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      )
    }

/ / ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` third part ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `

    // Execute initProxy function in non-production environment with instance; The _renderProxy attribute of the instance is set to the instance itself in production
    if(process.env.NODE_ENV ! = ='production') {
      initProxy(vm)
    } else {
      vm._renderProxy = vm
    }
    
    // Sets the _self attribute of the instance to the instance itself
    vm._self = vm
    // create component instance attributes ($parent, $children, $root, $refs, etc.)
    initLifecycle(vm)
    /** * initializes the custom event. There is a bit of caution here, so we use <comp@click="handleClick" /> The listener of the event is not the parent component, but the child component itself, that is, the event is sent and the listener is not the parent component
    initEvents(vm)
    Getthis. slots. Define this._c (createElement) as h function
    initRender(vm)
    // Call the preceding hook function to execute the beforeCreate lifecycle function
    callHook(vm, 'beforeCreate')
    Initializing Inject the Inject option gets configuration objects in the form of {key:val} and responds to parsing results, proxying each key to the VM instance
    initInjections(vm) // resolve injections before data/props
    // Data initialization is the core of the responsive principle, handling props Methods computed data Watch, etc
    initState(vm)
    // Parse the provide object on the component configuration item and mount it to the vm._provided property
    initProvide(vm) // resolve provide after data/props
    // Execute an Created lifecycle function by calling the created hook function
    callHook(vm, 'created') 
    // The beforeCreate life cycle can not access the data because it has not been initialized yet, but can get relational properties, slots, custom events

/ / ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` fourth part ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `

    /** ** if vm.$options has el attribute, call vm.$mount method to mount vm
    if (vm.$options.el) {
       // Call the $mount method to enter the mount phase
      vm.$mount(vm.$options.el)
    }
  }
}
Copy the code

initInternalComponent

/ * * *@description: Performance optimizations assign some configuration values passed in by components to vm.$options flatten properties on configuration objects to reduce run-time prototype chain look-up and improve execution efficiency *@param {*} Vm component instance *@param {*} Options pass in the configuration */

export function initInternalComponent (vm: Component, options: InternalComponentOptions) {
  
  // Create vm.$options based on the configuration object on the component constructor
  const opts = vm.$options = Object.create(vm.constructor.options)

  / / ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` configuring component incoming some assigned to the vm. The $options on ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` Sunday afternoon
  const parentVnode = options._parentVnode
  opts.parent = options.parent
  opts._parentVnode = parentVnode

  const vnodeComponentOptions = parentVnode.componentOptions
  opts.propsData = vnodeComponentOptions.propsData
  opts._parentListeners = vnodeComponentOptions.listeners
  opts._renderChildren = vnodeComponentOptions.children
  opts._componentTag = vnodeComponentOptions.tag

  / / ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` configuring component incoming some assigned to the vm. The $options on ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ∨

  // If there is a render function, assign it to vm.$options
  if (options.render) {
    opts.render = options.render
    opts.staticRenderFns = options.staticRenderFns
  }
}
Copy the code

resolveConstructorOptions

/ * * *@descriptionParse the options property on instance constructor and merge the base class option *@param {*} Ctor instance constructor *@return {*} Options Configures the options */

export function resolveConstructorOptions (Ctor: Class<Component>) {
  // Get configuration options from the instance constructor
  let options = Ctor.options
  if (Ctor.super) {
    /** * ctor. super is used to subclass Vue. Extend. The vue. extend method adds a super attribute to Ctor, If the constructor has super on it, Ctor is a subclass of Vue. Extend. In other words, Ctor checks for the parent component and then retrieves the configuration options on the base class recursively, that is, the set of all superior options */
    const superOptions = resolveConstructorOptions(Ctor.super)
    
    // Ctor. SuperOptions: Options on the parent component's Vue constructor, such as directives,filters,....
    const cachedSuperOptions = Ctor.superOptions

    if(superOptions ! == cachedSuperOptions) {// Update superOption if the parent component has been changed
      Ctor.superOptions = superOptions

      // Check for any late changes/additional options on ctor. options
      const modifiedOptions = resolveModifiedOptions(Ctor)

      if (modifiedOptions) {
        // If there are options that have been modified or added, merge the two options
        extend(Ctor.extendOptions, modifiedOptions)
      }

      // Options merge, and assign the merge result to ctor.options
      options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions)
      
      if (options.name) {
        options.components[options.name] = Ctor
      }
    }
  }
  // When ctor. super does not exist, such as using the new keyword to create a new instance of the Vue constructor directly returns the options of the underlying constructor
  return options
}

Copy the code

resolveModifiedOptions

/ * * *@description: Check for any late modifications/additional options *@param {*} Ctor instance constructor *@return {*} modified* /

function resolveModifiedOptions (Ctor: Class<Component>): ?Object {
  // Declare the modification
  let modified
  // Get the constructor option
  const latest = Ctor.options
  // Sealed constructor option, backup
  const sealed = Ctor.sealedOptions
  // Compare the two options and record the inconsistent options
  for (const key in latest) {
    if(latest[key] ! == sealed[key]) {if(! modified) modified = {} modified[key] = latest[key] } }// Return the modified item
  return modified
}

Copy the code

Code reading

Through the code, we break down the _init process into four parts. Here is a brief overview of what has been done, the specific code will be analyzed in detail later.

The first part

⭐ Each Vue instance has a _UID, which is incremented to ensure uniqueness.

⭐ vue instance should not be reactive, mark it.

The second part

⭐ If it is a child component, put some of the deeper properties on the component configuration object in the Vm. $options option to make the code more efficient.

⭐ If it is the root component, merge options, and vue will put all related properties and methods into vm.$options. The vm.$options attribute comes from two aspects, one is predefined by Vue’s constructor, vm.constructor, and the other is the input object passed in when new Vue.

The third part

⭐ initProxy/vm._renderProxy executes the initProxy function in a non-production environment. The _renderProxy attribute of the instance is set to the instance itself in production.

⭐ sets the _self attribute of the instance to the instance itself.

⭐ initLifecycle initializes component instance relationship properties ($parent, $children, $root, $refs, etc.)

⭐ initEvents Initializes custom events.

⭐ initRender initializes slots, gets this.slots, and defines this._c, the createElement method, as the h function normally used.

⭐ callHook executes the beforeCreate life cycle function.

⭐ initInjections initializes the Inject option

⭐ initState is the core of the responsive principle, which handles props, methods, computed, data, and watch.

⭐ initProvide parses the provide object on the component configuration item and mounts it to the vm._provided property.

⭐ callHook performs created lifecycle functions.

The fourth part

⭐ If there is an el attribute, the vm is mounted by calling the vm.$mount method with the goal of rendering the template into the final DOM.

⭐ If the EL does not exist, you need to manually mount it.

Let’s conclude with a mind map

reference

Vue. Js technology revealed

Proficient in Vue stack source code principles

This article by Li Yongning tutorial combined with their own ideas to sort out, in this special thanks to the predecessors.