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 fileinitGlobalAPI(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 theVue.configobject
  • Set up thekeep-alivecomponent
  • registeredVue.use()To register plug-ins
  • registeredVue.mixin()Implementation in
  • registeredVue.extend()Returns a component constructor based on the options passed in
  • registeredVue.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

  1. _init()
  • Defined in thesrc/core/instance/index.js
  • The constructor is defined and calledthis._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 callednew Vue(), called in the constructor_init()Method, which acts as an entry point for our entire Vue
  • in_initMethod, and finally called$mountThere are two of them$mountThe first definition is inentry-runtime-with-compiler.jsFile, which is our entry file$mountthe$mount()Is to help us compile the template intorenderFunction, but it first checks to see if it is currently passed inrenderOption, if it’s not passed in, it’s going to get ourstemplateOption, iftemplateAnd without options, he would have putelAs our template, and then compile the template intorenderThe delta function, which is passedcompileToFunctions()Function to help us compile the template intorenderDelta of delta of delta of delta of deltarenderOnce the function is compiled, it will putrenderThe function exists in ouroptions.renderIn the.
  • And then it callssrc/platforms/web/runtime/index.jsIn the file$mountMethod, which in this case is retrieved firstelBecause if it’s a runtime version, it won’t walkentry-runtime-with-compiler.jsThis entry gets the EL, so for the runtime version, we’ll retrieve the EL in $mount() of runtime/index.js.
  • Next callmountComponent()This method is insrc/core/instance/lifecycle.jsIs defined inmountComponent()In, first will judgerenderOption, if notrenderOption, 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 triggersbeforeMountThe hook function in this lifecycle, before the mount begins.
  • And then I defineupdateComponent(), in this function, callvm._renderandvm._update.vm._renderTo generate the virtual DOM,vm._updateThe role of will be virtualDOMConvert to realityDOMAnd mount it to the page
  • createWatcherObject under creationWatcherWhen, passedupdateComponentThis function, this function ends up atWatcherInternally called. inWatcherIt works on the insidegetMethod, which is triggered in the lifecycle when Watcher is createdmountedThe 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