Recently in the study of Vue source code, and then mainly on the first Vue rendering to do a summary ~
Take a look at the picture below first, and we’ll walk you through it step by step
Vue source address, here mainly look at the source directory below SRC
Start with the import file
Defined in SRC/platform/web/entry – the runtime – with – compiler. Js
Second, Vue initialization process
1. First take out Vue $mount, rewrite $mount, add new functions to $mount
// src/platform/web/entry-runtime-with-compiler.js
// Retain the $mount method for Vue instances
const mount = Vue.prototype.$mount
Vue.prototype.$mount = function ( el? : string | Element, //False for non-SSR and true for SSRhydrating? : boolean) :Component { // Get the el object el = el && query(el) .} Copy the code
2. Determine whether there is a render options, if not render options that will remove the template template, compile the template to render function, and then call the mount method, rendering the DOM.
3. Add a static compile method to Vue, which compiles HTML strings into render functions
if(! options.render) { let template = options.template
if (template) {
. }
} Vue.compile = compileToFunctions export default Vue Copy the code
4. This file registers the Transition and TransitionGroup components globally via extend, the v-model and V-show directives, and the _patch_ function on the Vue prototype. The function of _patch_ is to transform the virtual DOM into the real DOM. When assigning the value to the patch function, it will determine whether it is the browser environment. 5 we continue to look for the constructor of Vue
// src/platforms/web/runtime/index.js
extend(Vue.options.directives, platformDirectives)
extend(Vue.options.components, platformComponents)
// Check whether it is a browser environment Vue.prototype.__patch__ = inBrowser ? patch : noop Copy the code
“Initialize a static member“
6. Define in SRC /core/index.js
- Called in this file
initGlobalAPI(Vue)
Method to add static methods to the Vue constructor
initGlobalAPI(Vue)
Copy the code
InitGlobalAPI (Vue) is defined in SRC /core/global-api/index.js
- Initialize the
Vue.config
object - Set up the
keep-alive
component - registered
Vue.use()
To register plug-ins - registered
Vue.mixin()
Implementation in - registered
Vue.extend()
Returns a component constructor based on the options passed in - registered
Vue.directive()
.Vue.component()
.Vue.filter
export function initGlobalAPI (Vue: GlobalAPI) {
const configDef = {}
configDef.get = (a)= > config
if(process.env.NODE_ENV ! = ='production') {
configDef.set = (a)= > {
warn( 'Do not replace the Vue.config object, set individual fields instead.' ) } } // Initialize the vue.config object Object.defineProperty(Vue, 'config', configDef) // exposed util methods. // NOTE: these are not considered part of the public API - avoid relying on // them unless you are aware of the risk. // These tools are not considered part of the global Api, so don't rely on them unless you are aware of some of the risks Vue.util = { warn, extend, mergeOptions, defineReactive } // Static method set/delete/nextTick Vue.set = set Vue.delete = del Vue.nextTick = nextTick // ... Vue.options._base = Vue // Set the keep-alive component extend(Vue.options.components, builtInComponents) Vue. Use () is used to register plug-ins initUse(Vue) // Register Vue. Mixin () to implement mixin initMixin(Vue) // Register vue.extend () to return a component constructor based on the passed options initExtend(Vue) // Register vue.directive (), Vue.component(), vue.filter initAssetRegisters(Vue) } Copy the code
Initialize instance members
- _init()
- Defined in the
src/core/instance/index.js
- The constructor is defined and called
this._init(options)
methods - Common instance members are mixed into Vue
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')
} Call the _init() method this._init(options) } // Register the _init() method of the VM to initialize the VM initMixin(Vue) $data/$props/$set/$delete/$watch stateMixin(Vue) // Initialize event-related methods //$on/$once/$off/$emit eventsMixin(Vue) // Initialize the life-cycle related mixin method // _update/$forceUpdate/$destroy lifecycleMixin(Vue) / / in the render // $nextTick/_render renderMixin(Vue) export default Vue Copy the code
Initialize instance member init()
- When both the static and instance members are initialized, the Vue constructor is called, where the _init() method is called
- _init is initialized in initMixin, primarily for Vue instances
// The vm's life-cycle variables are initialized
initLifecycle(vm)
// The vm listens for events that the parent component is bound to on the current component
initEvents(vm)
// Vm compiler render initialization
// $slots/$scopedSlots/_c/$createElement/$attrs/$listeners initRender(vm) // beforeCreate The callback to the life hook callHook(vm, 'beforeCreate') Inject inject members into the VM initInjections(vm) // resolve injections before data/props // Initialize _props/methods/_data/computed/watch for the VM initState(vm) // initialize provide initProvide(vm) // resolve provide after data/props // created life hook callback callHook(vm, 'created') Copy the code
Initialize instance member initState()
Initialize _props/methods/_data/computed/watch of the VM
export function initState (vm: Component) {
vm._watchers = []
const opts = vm.$options
if (opts.props) initProps(vm, opts.props)
if (opts.methods) initMethods(vm, opts.methods)
if (opts.data) { initData(vm) } else { observe(vm._data = {}, true /* asRootData */) } if (opts.computed) initComputed(vm, opts.computed) if(opts.watch && opts.watch ! == nativeWatch) { initWatch(vm, opts.watch) } } Copy the code
-
In instance/state.js, we get $options from the Vue instance, and then check whether options has props,methods,data, computed, and watch attributes. If so, we initialize it with initProps InitProps (VM, opts.props) takes two parameters, one is the Vue instance, and the other is the props attribute. We jump to the initProps function and define an _Props object for the Vue instance and store it in a constant
const props = vm._props = {} Copy the code
-
It then iterates through all the properties of PropsOptions, which is essentially the second parameter in the initProps method. Each property is iterated over and injected into the Props object via defineReactive, which is the vm._props FineReacttive is converted to get and set, and finally stored on the Props object, “Notice”
-
In development mode, if we assign a value to this property directly, we will issue a warning,
-
Properties in props are converted to GET and set directly in production via defineReactive
-
Finally, we check whether the props attribute exists in the Vue instance. If not, we inject our properties into the Vue instance through the Proxy function
-
By calling in the Proxy Object. DefineProperty (target, key, sharePropertyDefinition)
conclusion
The function of initProps is to convert our Props members into responsive data and inject it into the Vue instance
initMethods
-
In initMethods (vm, Opts. Methods (), also receives two parameters, methods in the Vue instance and options, first obtains Props in the options, then iterates through all properties of methods, then determines whether the current development environment is functicon or not
-
If the methods method name exists in the Props object, a warning will be sent if the methods name exists in the Props object. The warning already exists in the Props object because both methods and Props are injected into the Vue instance
-
We continue to determine whether the key exists in Vue and call isReserved(key) to determine whether our key begins with an _ or $ Bind (methods[key], vm); / / bind(methods[key], vm)
conclusion
InitMethods is used to inject methods of options into the vue instance. Before injection, it checks whether the name exists in Props and the naming convention. _ and $are not recommended
initData(vm)
-
InitData (VM) is called when options has data option
-
Observe (vm._data = {}, true). Observe is one of the functions in the response
-
GetData (data, VM); getData(data, VM); getData(props,methods)
// src/core/instance/state.js
const keys = Object.keys(data)
const props = vm.$options.props
const methods = vm.$options.methods
Copy the code
Finally, do a reactive processing
observe(data, true)
Copy the code
At the end of the _init function, $mount is called again to mount the entire page
// src/core/instance/init.js
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
Copy the code
First render process summary
- Before rendering for the first time, Vue initialization is performed, initializing instance members and static members
- When initialization is complete, the Vue constructor is called
new Vue()
, called in the constructor_init()
Method, which acts as an entry point for our entire Vue - in
_init
Method, and finally called$mount
There are two of them$mount
The first definition is inentry-runtime-with-compiler.js
File, which is our entry file$mount
the$mount()
Is to help us compile the template intorender
Function, but it first checks to see if it is currently passed inrender
Option, if it’s not passed in, it’s going to get ourstemplate
Option, iftemplate
And without options, he would have putel
As our template, and then compile the template intorender
The delta function, which is passedcompileToFunctions()
Function to help us compile the template intorender
Delta of delta of delta of delta of deltarender
Once the function is compiled, it will putrender
The function exists in ouroptions.render
In the. - And then it calls
src/platforms/web/runtime/index.js
In the file$mount
Method, which in this case is retrieved firstel
Because if it’s a runtime version, it won’t walkentry-runtime-with-compiler.js
This entry gets the EL, so for the runtime version, we’ll retrieve the EL in $mount() of runtime/index.js. - Next call
mountComponent()
This method is insrc/core/instance/lifecycle.js
Is defined inmountComponent()
In, first will judgerender
Option, if notrender
Option, but we passed in the template and are currently in a development environment to send a warning if we are currently using the runtime version of Vue and we did not pass it inrender
, but the template is passed in telling us that the runtime version does not support the compiler. And then it triggersbeforeMount
The hook function in this lifecycle, before the mount begins. - And then I define
updateComponent()
, in this function, callvm._render
andvm._update
.vm._render
To generate the virtual DOM,vm._update
The role of will be virtualDOM
Convert to realityDOM
And mount it to the page - create
Watcher
Object under creationWatcher
When, passedupdateComponent
This function, this function ends up atWatcher
Internally called. inWatcher
It works on the insideget
Method, which is triggered in the lifecycle when Watcher is createdmounted
The hook function, in the get method, is calledupdateComponent()
- The mount ends and the Vue instance is finally returned.
This is how Vue renders for the first time
Thank you for your
Thank you for taking the time to read this article. If you find it helpful, please give it a thumbs up (🌹🌹🌹).
This article is formatted using MDNICE