new VueThe instance

The whole process

Initialization and responsive processing of data

// The overall process
new Vue()

this._init(options)

// Call the _init method bound in initMixin(Vue)
Vue.prototype._init = function(options) { const vm =  this }

// a series of initialization operations initLifecycle, initEvents, initRender... initState, ...

/ / a mount
vm.$mount(vm.$options.el) // #app
Copy the code
// Focus on the initState method
export function initState(vm) {
  / / merge options
  vm.$options = mergeOptions( ... )
  
  const opts = vm.$options
  initProps(vm, opts.props)
  initMethods(vm, opts.methods)
  initData(vm) / / concerns
  initComputed(vm, opts.computed)
  initWatch(vm, opts.watch)
}
Copy the code
/ / initData method
function initData(vm) {
  const data = vm.$options.data
  // whether data is function, note vm._data
  data = vm._data = typeof data === 'function' ? getData(data, vm) : data || {}
  
  // Check if the property conflicts with the properties defined in props, methods
  const keys = Object.keys(data)
  // ... 
  
  // Pass this._data. XXX to this.xxx via object.defineProperty
  // get: return this._data.xxx
  // set: this._data.xxx = val
  proxy(vm, `_data`, key)
  
  // Reactive processing
  observe(data, true /* asRootData */)}Copy the code

VueExamples of the mount

/ / Add vNode to vNode (vm._update()); / / add vNode to vNode (vm._update()); / / Add vNode to vNode (vm._update())

The version entry for analysis is entry-runtime-with-compiler.js

const mount = Vue.prototype.$mount // Cache - Runtime only Version uses the mount method directly
Vue.prototype.$mount = function() {} // redefine

// render and template respectively
// Will be converted to render function
const { render } = compileToFunctions()
vm.$options.render = render

// Call the $mount method on the original prototype (i.e. cached) to mount it
return mount.call(this, el, hydrating) // The hydrating server render is relevant. Default is false

Execute the mountComponent method in the mount method
return mountComponent(this, el, hydrating)
Copy the code
The mountComponent method does two main things

Call vm._render() to generate a virtual node
const vnode = vm._render()

// 2. Instantiate watcher and call updateComponent - initialization & data changes are performed
new Watcher(vm, updateComponent, noop, {}, true)
updateComponent = () = > {
  vm._update(vm._render(), hydrating) / / update the dom
}

// The process ends, changing the state
vm._isMounted = true
callhook(vm, 'mounted')
Copy the code

renderfunction

src/core/instance/render.js

Vue.prototype._render = function() {
  const vm = this
  // The entry section handles the render function
  const { render } = vm.$options
  
  // Core part -vm.$createElement
  vnode = render.call(vm._renderProxy, vm.$createElement)
  
  return vnode
}

The $createElement method is defined in initRender(vm)
Copy the code
// examples of projects using the render function
import Vue from 'vue'

new Vue({
  el: '#app'.// createElement -> vm.$createElement
  render: function(createElement) {
    return createElement('div', {
      attrs: {
        id: 'app'}},this.message)
  },
  data() {
   return {
    message: 'hello, vue'}}})Copy the code

virtual dom

Native JS objects to describe a DOM node refer to the open source library SnabbDOM

createElement

Create a VNode SRC/core/vdom/create – element. Js

// Encapsulate one layer of _createElement
export function createElement() {
  return _createElement(context, tag, data, children, normalizationType)
}
// context - VNode 上下文环境: Component
// data - VNode 数据: VNodeData
// children -vnode child: any - needs to be normalized as a standard VNode array

/ / normalizationType - byte point specification types - 【 】 to distinguish function compiled | | written by the user
Copy the code
// src/core/instance/render.js
export function initRender(vm) {
  vm._c(vm, a, b, c, d, false) // render functions complied from template.
  vm.$createElement(vm, a, b, c, d, true) // user-written render functions.
}

/ / normalizationType category
// false - simpleNormalize
// true - alwaysNormalize

// To sum up
// render functions generate - false - simple - call simpleNormalizeChildren
// render functions are user handwriting - true-always - call normalizeChildren
Copy the code
// src/core/vdom/helpers/nomalize-children.js
export function simpleNormalizeChildren(children) {
  // The default VNode type, but functional components return arrays instead of roots
  // 1-level deep
  for(let i = 0; i < children.length; i++) {
    if(Array.isArray(children[i])) {
      return Array.prototype.concat.apply([], children)
    }
  }
  return children
}

// Two scenarios
// 1. User handwriting, children only have one node, create simple text node
// 2. 
      
export function normalizeChildren(children) {
  return isPrimitive(children) // Whether it is a basic type
  ? [createTextVNode(children)] // Create simple text nodes
  : Array.isArray(children)
  ? normalizeArrayChildren(children)
  : undefined  
}
export function normalizeArrayChildren(children) {
  / / traverse the children
  // Call this method recursively if the child node c is Array
  // Call createTextVNode() if child c is of base type
  
  // opt: If there are consecutive text nodes, they are merged into a single text node
}
Copy the code
/ / create a VNode
if(typeof tag === 'string') {
  // 1. Built-in node
  vnode = new VNode(parsePlatformTagName(tag), data, children, undefined.undefined, context)
  // 2. Registered component name
  vnode = createComponent(Ctor, data, context, children, tag)
  // 3. Unknown node
  vnode = new VNode(tag, data, children, undefined.undefined, context)
} else {
  vnode = createComponent(tag, data, context, children)
}
return vnode

// vm._render() completes the process
Copy the code

update

Core – vm. Patch () for the first time rendering – concerns data update – reactive principle of SRC/core/instance/lifecycle. Js

Vue.prototype._update = function(vnode, hydrating) {
  // Core part
  vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false)}// src/platforms/web/runtime/index.js
Vue.prototype.__patch__ = inBrowser ? patch : noop // There is no DOM environment for server rendering
// src/platforms/web/runtime/patch.js
export const patch = createPatchFuntion({nodeOps, modules }) // Patch is implemented
Copy the code
// src/core/vdom/patch.js
export function createPatchFunction(backend) {
  // Core - Create a real DOM from a virtual node and insert a parent node
  createElm() {
    // Iterate over the child virtual nodes recursively - depth-first
    // Recursively, child elements take precedence over insert, so the insertion order of vNode tree is parent before child
    createChildren()
  }
}

// Invoke native DOM API operations
function insert(parent, ele, ref) {
  // e.g.
  // insertBefore()
  // appendChild()
}
Copy the code

The main process is shown in the figure below