“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 itZIP
Format file, and then you need to open the artifactVScode
.
After opening the editor, all you need to do is:
- Install dependencies
install
— YARN or NPM - find
package.json
File and find what’s insidescripts
Part of it, and then godev
Add to command--sourcemap
Configure parameters, or create a new onedev:sourcemap
Command, its content is thandev
One more command--sourcemap
Configuration, in fact, is mainly for generationvue.js.map
The file is convenient for debugging later
- perform
npm run dev:sourcemap
The command, once successfully executed, will be indist
Directory generationvue.js.map
file
- And then you can go to
example
Write down some examples you want to test and passdebug
Find 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.js
和TARGET:web-full-dev
It 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 the
example
Create a new directory under the directory. It can be any name. This article discusses the initialization, so it will be calledinit
In theinit
Create a new one in the directoryhtml
File, in which to introducedist
In the directoryvue.js
Because of the generatedmap
The file isvue.js.map
, otherwise,debug
Is not convenient to find the corresponding file location
I’m going to choose option two, because option one passesrollup
Configuration search is still too tedious, so throughdebug
You can quickly determineVue
The 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.js
In 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 components 和 The 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 the
vm
Constructor to create a new configuration object that is normally accessed$options
object - Flatten the current component configuration item and assign it to
$options
Object, avoiding the dynamic lookup of the prototype chain - If exists in the current component configuration item
render
Option, just add it to$options
On 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 constructor
super
Attribute 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 and
extent
Options 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
_c
Methods, i.e.,createElement
The method, which is equal toh
function - right
$attrs
和$listeners
Property 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 methodinject
The choices were already normalized before they got here, so this right hereinject
The options must be of the following format:inject = { key: { from: xxx, default: xxx } } Copy the code
- traverse
inject
All configuredkey
, find the correspondingprovide
The values in the- from
inject
Obtaining from Configurationfrom
Attribute values - The loop looks in the ancestor component
provide
If found, get the corresponding value and save toresult
; If it does not, it continues up to the root component
- from
- If the root component is still not found
inject
In thekey
On the corresponding ancestor componentprovide
Value, then checkinject
Is 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
$options
Get on theprovide
options provide
If the option exists, check whether it is a function. If it is, call it and get the configuration object. If it is not, use itprovide
options- in
vm
Instance mount_provide
Property, and the value is the one aboveprovide
The 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 components
和Global component for user registration
, will eventually be incorporated into the configuration of the following componentcomponents
In the options{ components:{xxx} }
Local registration, which performs compiler generationrender
Function 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
_c
Methods, i.e.,createElement
The method, which is equal toh
function
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 the
inject
Option to find the corresponding from the ancestor component configuration itemprovide
Option to get the correspondingkey
The value of, is obtainedresult[key] = val
Result of form - If it does not already exist on the root component, determine if it does
default
If yes, set the default value - To get the
result
The results are processed in a responsive, surrogate wayvm
instance
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?