“Live up to the time, the creation of non-stop, this article is participating in 2021 year-end summary essay competition”

preface

Recently, I want to learn the source code of Vue2, the main purpose is to learn the source code of Vue3 later, so that I can have a better comparison and understanding, so this series will not involve the content of Vue3 for the time being, but the core module of Vue3 is the same as that of Vue2. Only in the implementation of the way to change, optimization and so on.

The preparatory work

Before you start reading the source code, there is something you must do, and that is pullSource warehouse codeOr just download itZIPFormat file, and then you need to open the artifactVScode .

After opening the editor, all you need to do is:

  • Install dependenciesinstall— YARN or NPM
  • findpackage.jsonFile and find what’s insidescriptsPart of it, and then godevAdd to command--sourcemapConfigure parameters, or create a new onedev:sourcemapCommand, its content is thandevOne more command--sourcemapConfiguration, in fact, is mainly for generationvue.js.mapThe file is convenient for debugging later

  • performnpm run dev:sourcemapThe command, once successfully executed, will be indistDirectory generationvue.js.mapfile

  • And then you can go toexampleWrite down some examples you want to test and passdebugFind the location of the corresponding content in the code

Deep source

The code location of Vue initialization

To get into the details of Vue initialization, we need to find out where Vue initialization takes place. There are two ways to do this:

  • Use the package.json file to do the lookup— in script script command configuration "dev": "rollup -w -c scripts/config.js --sourcemap --environment TARGET:web-full-dev", in which thescripts/config.jsTARGET:web-full-devIt indicates the specific configuration in the file, and then you can find the corresponding entry file layer by layer
  • Search in debug mode– the first in theexampleCreate a new directory under the directory. It can be any name. This article discusses the initialization, so it will be calledinitIn theinitCreate a new one in the directoryhtmlFile, in which to introducedistIn the directoryvue.jsBecause of the generatedmapThe file isvue.js.map, otherwise,debugIs not convenient to find the corresponding file location

I’m going to choose option two, because option one passesrollupConfiguration search is still too tedious, so throughdebugYou can quickly determineVueThe location of the file to initialize.

Initialization enclosing _init (options)

In SRC >core>index.js, we can clearly see that when we call new Vue(), we call the this._init() method, which is defined in initMixin(Vue)

InitMixin (Vue) method

insrc>core>init.jsIn the file, you can see it ininitMixin()The core of the method is the part that deals with component configuration items, which is divided intoChild componentsThe root componentAnd corresponding to the configuration ofinitInternalComponent()Methods andmergeOptions()Method +resolveConstructorOptions()Methods.

There are also calls to these methods in vue.prototype. _init, each of which will be read in turn:

Child component — initInternalComponent() method

What this method does is create the $options object and flatten the component options to optimize performance. Components have many configurations, and there are also various nested configurations, which can be accessed dynamically through the prototype chain, which affects execution efficiency.

  • According to thevmConstructor to create a new configuration object that is normally accessed$optionsobject
  • Flatten the current component configuration item and assign it to$optionsObject, avoiding the dynamic lookup of the prototype chain
  • If exists in the current component configuration itemrenderOption, just add it to$optionsOn the object

The root component – resolveConstructorOptions () method

In SRC > core > init. Js file, resolveConstructorOptions () method is the main thing is parsing configuration object from the constructor, specific as follows:

  • If the constructorsuperAttribute exists to prove that there is a base class, in which case the configuration options need to be resolved recursively
  • The base class configuration items of the constructor are cached and compared against the current configuration items. If they are inconsistent, the base class configuration items have changed
  • Find the configuration items that have been changed andextentOptions are merged and assigned to$options

The root component — mergeOptions() method

In the SRC >core>options.js file, the mergeOptions() method mainly does:

  • Standardize configuration options
  • Merges the incoming raw configuration objects
  • Returns the new configuration object

To merge configuration items of the root component, merge global configuration items to local configuration items of the root component. For example, merge globally registered Vue.componet(options) global configuration items to new Vue(options) of the root component.

   new Vue({
     el: xxx,
     data: { xxx },
     componets:{
       localComponents,
       globalComponents,
     }
   })
Copy the code

InitLifecycle () method

The initLifecycle() method is called in SRC >core>init.js with SRC >core> life.js.

While many might mistake this method for initializing the lifecycle hook function (because of its name), it primarily initializes component relational properties, such as $root, $parent, $children, $refs, and so on.

InitEvents () method

The initEvents() method is called in the SRC >core>init.js file, defined as SRC >core>events.js.

The main function is to initialize custom events, but for this method at present, there is a simple understanding, because it involves more processing, so this article will not expand it temporarily, but later related to the method on this instance in the specific analysis.

$emit(‘ myclick ‘) :


Answer: You might think that the parent component of comP is listening, but the com component itself is listening, $on(‘ myclick ‘, function clickHandle(){}) and this.$emit(‘ myclick ‘); Where this refers to the component itself.

InitRender () method

Call the initRender() method in SRC >core>init.js with SRC >core>render.

The specific content here is no longer expanded, and the render part is involved in in-depth interpretation. In fact, it mainly does three things:

  • Initialize the slot, for example:Vm. $slots, vm. $scopedSlots
  • define_cMethods, i.e.,createElementThe method, which is equal tohfunction
  • right$attrs$listenersProperty for reactive processing

CallHook (VM: Component, hook: string) method

In the SRC >core>init.js file, callHook(vm, ‘beforeCreate’) and callHook(VM, ‘created’) are called, which is how the lifecycle functions defined in the component configuration items are normally called.

The callHook method is defined in SRC >core>lifecycle.

InitInjections () method

Call the initinjection () method in SRC >core>init.js, where the method is defined as SRC >core>inject.js.

For details about provide/ Inject and how to use them, click the vUE document.

InitInjections () method

The main thing to do is to obtain the core option result after parsing, and then delegate each item of result to the VM instance, which can also be understood as responsive processing, and directly access in the form of this.key in the component

ResolveInject () method

  • resolveInject(inject: any, vm: Component)In the methodinjectThe choices were already normalized before they got here, so this right hereinjectThe options must be of the following format:
     inject = {
       key: {
          from: xxx,
          default: xxx
        }
     }
    Copy the code
  • traverseinjectAll configuredkey, find the correspondingprovideThe values in the
    • frominjectObtaining from ConfigurationfromAttribute values
    • The loop looks in the ancestor componentprovideIf found, get the corresponding value and save toresult; If it does not, it continues up to the root component
  • If the root component is still not foundinjectIn thekeyOn the corresponding ancestor componentprovideValue, then checkinjectIs the default value set in, and if so, it is assigned to the default value

InitState () method

Call the initState() method in the SRC >core>init.js file. The method is defined as SRC >core>state.js.

As the core of the responsive principle, it mainly deals with props, data, methods, watch, computed, and so on. Because this is a part of the responsive content, it will not be discussed in depth in this paper.

InitProvide () method

The initProvide() method is called in the SRC >core>init.js file with SRC >core>inject.js.

It’s very simple:

  • from$optionsGet on theprovideoptions
  • provideIf the option exists, check whether it is a function. If it is, call it and get the configuration object. If it is not, use itprovideoptions
  • invmInstance mount_provideProperty, and the value is the one aboveprovideThe specific content of

conclusion

The above analysis is based on each of the methods used in the vue.prototype. _init initialization function, which needs to be summarized here, along with some questions to understand.

Merge component configuration

Child components

When subcomponents merge configuration items, they flatten the configuration items to reduce the dynamic search of prototype chain and achieve the purpose of performance optimization.

The root component

Root component merge configuration is to merge global configuration items into root component local configuration items.

Root component merging occurs in three places:

  • That’s what happens when you initialize it
  • Vue.component(name, Comp), will mergeVue has built-in global componentsGlobal component for user registration, will eventually be incorporated into the configuration of the following componentcomponentsIn the options
  • { components:{xxx} }Local registration, which performs compiler generationrenderFunction to merge the global configuration object onto the component local configuration object

Initialization of component relationship properties

If you need to initialize $root, $parent, $children, $refs, etc.

Initializes custom events

Question: When a custom event is used on a component, who is responsible for listening for the event, parent or child?

 // This is a pseudo-code
  <parentComp>
    <comp @myClick="clickHandle" />
  </parentComp>
Copy the code

$emit(‘myClick’, function clickHandle(){}); $emit(‘myClick’, function clickHandle(){}); This is the component instance, meaning that whoever needs to fire the event needs to listen for the event.

Initialize slot & define _c method

  • Initialize the slot, for example:Vm. $slots, vm. $scopedSlots
  • define_cMethods, i.e.,createElementThe method, which is equal tohfunction

Execute beforeCreate and created lifecycle functions via callHook

Q: What can beforeCreate fetch and access? Can data be accessed?

It’s easy to see from the source code that only component relationship properties, custom events, slots, and _c methods are initialized before beforeCreate, so that’s all you can access.

Because data, props, methods, etc. are not initialized, they will not be able to be accessed. If you use the method for the forecast object asynchronously, such as setTimeout, for example, it can be accessed asynchronously. The first place you can access data is actually created.

Initialize the Inject option

  • According to theinjectOption to find the corresponding from the ancestor component configuration itemprovideOption to get the correspondingkeyThe value of, is obtainedresult[key] = valResult of form
  • If it does not already exist on the root component, determine if it doesdefaultIf yes, set the default value
  • To get theresultThe results are processed in a responsive, surrogate wayvminstance

Initialize state data

The core of the responsive principle mainly deals with props, data, methods, Watch, computed, and so on

Handle the Provide option

Obtain the provide option from the vm.$options configuration object. If the provide option exists, determine if it is a function. If it is a function, obtain the return configuration item; otherwise, use the provide option

$mount mount

$options determines whether to automatically call $mount to enter the mount phase. If no, you need to manually call $mount to mount the el option.

The last

Source in the process, he must learn to give up some of the content, for this you have to know and study the main content, otherwise it is easy to produce all sorts of regional problems when reading the source code, thus blocking the main content, the corresponding modules in learning content of the corresponding interpretation is good, not a one-time reading all of the content.

Read the next article: VUE source Code: How to understand vUE responsiveness?