According to the Demo configuration, run the demo, then ignore the branch story, just analyze the main flow of Vue running.

Introduce Vue and App

To execute index.js, run:

import Vue from 'vue';
import App from './app.vue';
Copy the code
  • variableVueVueConstructor, in executionVueThe file will be initialized during the processVueThe prototype variable method of,WatchClass,DepClass and so on.
  • variableAppFor afterwebpackCompile, passVue-loader, VUe-template-compiler, VueLoaderPluginInclusion after actionrenderstaticRenderFnsComponent option object:
{
  name: "app"Data: ƒ data() components: {Child: {... }} props: {num: ƒ.nameƒ} beforeCreate: ƒ beforeCreate() created: ƒ created() beforeMount: ƒ beforeMount() Mounted: ƒ Mounted () : ƒ beforeUpdate() updated: ƒ updated() ƒ : ƒ ()true
  __file: "src/app.vue"
}
Copy the code

Where staticRenderFns contains an array of render functions generated separately by vNode marked as static nodes.

To deal withvm.$options

Execute new Vue(), that is, execute _init on the Vue prototype chain, internally execute:

if (options && options._isComponent) {
  initInternalComponent(vm, options);
} else {
  vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor), options || {}, vm);
}
Copy the code

Execute different methods depending on whether the passed options contain the component identifier.

initInternalComponent

If it is a component call, execute initInternalComponent to set vm.$options.

In the case of the first App component, the options method assigns the component’s options to the vm.$options prototype. $options = vm.$options = vm.

{
parent: Vue {_uid: 0._isVue: true.$options: {... },_renderProxy: Proxy._self: the Vue,... }// Parent component instance
_parentVnode: VNode {tag: "vue-component-1-app".data: {... },children: undefined.text: undefined.elm: undefined,... }/ / component vnode
propsData: {title: 1.name: "one"} // Props on component vNode
_parentListeners: {welcome: ƒ} // Events on component vNode
_renderChildren: undefined / / slots vnode
_componentTag: "app" // Component vNode component instance name
}
Copy the code

The prototype is the options property (defined in vue.extend as the component options object after mergeOptions) mounted under the child component constructor.

resolveConstructorOptions

If it is not a component resolveConstructorOptions and mergeOptions Settings vm. $options.

The Ctor argument is the passed vm.constructor, or Vue constructor. Options is vue. options, which is defined in the initGlobalAPI method. Ctor.options for this demo are:

{
  components: {KeepAlive: {... },Transition: {... },TransitionGroup: {... }} directives: {model: {... },show: {... }} filters: {} _base: ƒ Vue(options)}Copy the code

Ctor. Options: Ctor. Options: Ctor. ExtendOptions recursively merges Ctor. ExtendOptions with its parent constructor’s options, and returns the merged options.

mergeOptions

Check whether the options.components name is valid by executing the checkComponents method on the child (options). Then according to the options configuration, then check and format the Props, Inject, and Directives. MergeOptions is then recursively called to merge extends and mixins based on whether they exist.

Call mergeField to the parent (resolveConstructorOptions (vm) constructor)) and child (options) the strats processing. Strats is used to merge processing options. After merging, data is mergedInstanceDataFn. Finally, assign options to the instance $options property. Get the vm. $options:

{
  components: {App: {... },Bppƒ} cache: {} filters: {} _base: ƒ Vue(options) EL:"#main"Data: ƒ mergedInstanceDataFn() computed: {computeƒ} the methods: {plus: ƒ.hideƒ} watch: {b: {... ƒ}} beforeCreate: [ƒ] Created: ƒ] beforeMount: ƒ]Copy the code

Initialize the

Then execute:

initProxy(vm);
/ /...
initLifecycle(vm);
initEvents(vm);
initRender(vm);
Copy the code

The initialization contents are analyzed as follows:

initProxy

Renderproxy = new Proxy(VM, Handlers); Handlers are hasHandler.

Handlers are getHandler if options has render and _withStripped is true.

initLifecycle

$parent, $root, $children, _watcher, _isMounted;

$parent, $root, $child, $child, $child, $child, $child, $child

If parent-options. abstract is true, update $parent of the keep-alive component to the parent of the keep-alive component.

initEvents

If it is a child component, check whether $options._parentListeners are events on the component Vnode. If so, execute vm.$on to listen for custom events on the current sub-component instance, which are triggered by VM.$emit.

$ON, $EMIT is essentially a publish subscription. The $ON collection subscription is mounted under the _events property of the instance and $EMIT executes a list of subscribe events.

initRender

Initialize render related functions _c, $createElement, etc., and then listen on the instance:

  • $attrsContains non-action in parent scopepropFeature bindings identified (and retrieved)
  • $listenersContains the parent scope.nativeModifier of)v-onEvent listener)

Here are two attributes (each new a LIST of Dep subscribers).

If it is a child component, _parentVnode is assigned to vm.$vnode.

If there are regular slots, named slots, scopedSlots, etc., then initialize $slots, $scopedSlots.

Triggers the beforeCreate hook

callHook(vm, 'beforeCreate');
Copy the code

Execute the lifecycle hook beforeCreate and print vue beforeCreate.

The summary of this chapter

  1. This chapter introducesvueperformbeforeCreateStage;
  2. Merge handles componentsoptionsThe parent componentoptionsPlatform initializationoptions,vm.$options;
  3. Initialization is lifecycle specificVueVarious properties of instances, such as parent-child relationships$parentInitialization, etceventEvent delivery related;
  4. Initialize the render relatedVueFunctions on instances, slots, etc.