This series of articles thanks to Atri CXR’s Mini-Vue

1 Parses the App and gets onevnodeThe following operations are all based on vNode

// main.js
createApp(App).mount(rootContainer)

function createApp(rootComponent) {
  return {
    // Write a container first, since vue3 passes a selector, use a container first
    // To render the App rootComponent into the root container
    mount(rootContainer) {
      // Change rootComponent to a vnode (rootComponent->vnode)
      // All subsequent logic is processed based on this virtual node
      const vnode = createdVnode(rootComponent)
      // Accept a vnode and a virtual node
      render(vnode, rootContainer)
    }
  }
}

// h also calls createdVnode
function createdVnode(type,props? ,children?) {
	const vnode = {
  	type,
    props,
    children
  }
  return vnode
}
// Unpack the App at the first layer
// vnode = {
// children: undefined
// props: undefined
// type: {render: ƒ, setup: ƒ}
// }
Copy the code

2 Then call the render function to rendervnodeAnd the container#rootPass it, call it internally as it ispatchmethods

// Call path for recursive processing
function render(vnode, container) {
  patch(vnode, container)
}

function path(vnode,container) {
	if(vnode.type === 'string') {
  	processElement(vnode,container)
  }else if(isObject(vnode.type)) {
  	processComponent(vnode,container)
  }
} 
Copy the code

3 Handle component types

// To get an example, unpack until type is element.

The // component type finally yields an instance
instance = {
 	render: ƒ render (),setupState: {msg: 'mini-vue'},
  	type: {render: f, setup: ƒ}.vnode: {
  		type: {
    		render: ƒ render ()setup: ƒ setup()
    	}, 
    	props: undefined.children: undefined}}Copy the code
// Process components
function processComponent(vnode,container) {
	mountComponent(vnode,container)
}
// Initialize the component
function mountComponent(vnode,container) {
  // Get an instance instance
  const instance = createComponentInstance(vnode)
  // Complete the instance attribute
  setupComponent(instance)
  setupRenderEffect(instance,container)
}

// Create a component instance
function createComponentInstance(vnode) {
	const component = {
  	vnode,
    // For later use
    type:vnode.type
  }
}
function setupComponent(instance) {
	//TODO: initProps
  //TODO:  initSlots
  // Initialize stateful components
  setupStatefulComponent(vnode)
}
// Deconstruct setup and execute
function setupStatefulComponent(vnode) {
		const Component = vnode.type
    const { setup } = Component
    In one case, the user might not write setup
    if(setup) {
    	/ / the setup
      const setupResult = setup()
      handlerSetupResult(instance,setupResult)
    }
}

function handlerSetupResult(instance,setupResult) {
	// setup is an object, function is an object
  if(typeof setupResult === 'object') {
  	instance.setupState = setupResult
  }
  finishComponentSetup(instance)
}

function finishComponentSetup(instance) {
	const Component = instance.type
  // Suppose the user must write render
  instance.render = Component.render
}

function setupRenderEffect(vnode,container) {
  // Call render's h method, which calls createdVnode
	const subTree = vnode.render()
  // Continue calling the path method and continue unpacking
  path(subTree,container)
}

Copy the code

4 Handle the Element type

// Handle the element type
function processElement(vnode,container) {
	mountElement(vnode,container)
}
// Initialize element
function mountElement(vnode,container) {
  // vnode is the data returned by the function h (type,props,children)
	// Create the element
  const el = document.createElement(vnode.type)
  // Check if children is an array. If so, continue unboxing and call path
  const { children } = vnode
  // If it's not an array, it's a string. Call el.textContent
  if(typeof children === 'string') {
  	el.textContent = children
  }else if(Array.isArray(children)){
  	mountChildren(vnode, el)
  }
  / / generated props
  const { props } = vnode
  for(const key in props) {
    const val = props[key]
  	el.setAttribute(key, val)
  }
  / / into the container
  container.appendChildren(el)
}

function mountChildren(vnode,container) {
	vnode.children.forEach(v= >{
  	patch(v,container)
  })
}


Copy the code

This article repository address is github