Vue3 design idea -- implement a simple createApp factory function

Vue3 design idea – implement a simple createApp factory function

Compared with Vue 2, Vue 3 has made a qualitative leap, especially a lot of low-level logic work. The speed of vue3 is much happier than before. With Vite, developers can have a better development experience.

Looking at the code, we can see that the instance created after createApp() can be immediately followed by a mount method, but the bottom layer actually has a compilation process. After writing, you will gain a lot. Originally, you can design like this!

Differences in creating instances

vue3 implements the factory function createApp at the bottom, instead of using the instance generated by new Vue() like vue2, and exposes many methods in vue2, many of which are directly encapsulated in the instance object of the component.

import { createApp,render,h } from 'vue'
/*
	In vue3, these things are provided to various components in an exposed way. If there are components, they will be introduced. This benefit is very conducive to the tree shaking optimization of the whole project. There will be no unnecessary components, which will greatly save the space for the final project packaging
*/

What did you do during mount

mount() we all know that it is mounted. How is it mounted? What is the actual operation? In fact, there are many things to do.

  • According to the selector passed in by the user, the element selected by the selector is used as the host element
  • After getting the host element, get the innerHTML of this element as the template, and compile to get the rendering function - according to the rendering function, you can really get the DOM node (which is finally generated according to the state data passed in by the user)
  • Finally, the DOM node generated by the render function is appended to the host element

Understanding of the compilation process

The browser does not know some vue style syntax, such as {}, @ click, v-if and other special instructions. Therefore, before the mount method is executed and finally mounted on the host element, it needs to be compiled to process these instructions into the syntax recognized by the browser.

The real part is extremely complex and the amount of code is extremely large. What I deal with here is only the simplest way to deal with {}} interpolation expressions. At the same time, I castrate the dynamic DOM and generate only a dead h3 tag. We just need to understand the design idea. My requirements for myself are not so high for the time being. It's OK to go to this step.

After compilation, a render function will be generated.

Understanding of render function

render is a function. We only need to understand that after executing a function, an object with real DOM will be returned.

In the vue component, you can write the render method yourself or not. Therefore, according to this detail, we know to judge whether the configuration object passed in by the user contains the render method. If not, use your own render method

Compatibility between composition API and option API

The composition API is to write the setup function at the code block. The option API is the code style of vue2 by writing various configuration items.

The proxy api of ES6 is used here

this.proxy = new Proxy(this, {
  get(target, key) {
    if (key in target.setupCtx) {
      return target.setupCtx[key]
    } else {
      return target.dataCtx[key]
    }
  },
  set(target, key, value) {
    if (key in target.setupCtx) {
      target.setupCtx[key] = value
    } else {
      target.dataCtx[key] = value
    }
  }
})

The above is the part of the agent when we visit this When a value of proxy is, it will enter the get method. In the get method, priority judgment and other operations can be performed. If the setupAPI is used, it will be taken from the setup function, otherwise it will be taken from the data in the traditional option API. The same is true for setting values

proxy and object The api style of defineproperty is very similar, but it has higher performance and can do more things at the same time. The specific functions are described in detail in the Red Treasure book

Code part

The code is not long, but it is worth reading it several times. I also read some source code myself and wrote it down with the teacher. The harvest is great.

function createApp(config) {
  let app = {}
  app.mount = function (id) {
    // Host element
    this.rootDOM = document.getElementById(id) 

    if (!config.render) {
      /*
        Judge whether the incoming configuration item has a render method. If not, generate the render method by compiling
      */
      config.render = this.compile(this.rootDOM.innerHTML)
      // Compiling the innerHTML part of the host element is mainly to process interpolation expressions such as {} @ v-if and specify to compile into code recognized by the browser
    }

    if (config.setup) {
      this.setupCtx = config.setup()
    } else {
      this.dataCtx = config.data()
    }
    /*
      Encapsulates a proxy object proxy, compared with object Defineproperty has higher performance and can proxy to other objects. It has APIs that are well compatible with vue2 and vue3
    */
    this.proxy = new Proxy(this, {
      get(target, key) {
        if (key in target.setupCtx) {
          return target.setupCtx[key]
        } else {
          return target.dataCtx[key]
        }
      },
      set(target, key, value) {
        if (key in target.setupCtx) {
          target.setupCtx[key] = value
        } else {
          target.dataCtx[key] = value
        }
      }
    })
    /*
      Here, the proxy is passed into the get method of the proxy. In the future, a value accessing the proxy will enter the get method of the proxy 
        get Method will judge whether the setup api is used again. If yes, use the setup api. If not, use the option api
    */
    const el = config.render.call(this.proxy)
    this.rootDOM.innerHTML = ''
    this.rootDOM.appendChild(el)
    return this
  }
  app.compile = function (template) {
    /*
      This is a castrated version of the h3 tag
        
      Especially in the full version, we will parse the DOM according to the template and replace the {Title}} in the DOM with the title of the data passed in by the user
        At present, just to understand the process of mount, we have written a castration version, but by writing it down, we can well understand and understand the function and significance of Mount function
    */
    return function () {
      const h3 = document.createElement('h3')
      h3.textContent = this.title
      return h3
    }
  }
  return app
}

// Use process
const app = createApp({
  data(){
    return {
      title:'haihai'
    }
  },
  /*
    vue3 It is compatible with vue2api. In fact, the logic is implemented through proxy, a new API of ES6
      proxy You can judge whether there is a setup function or not by proxy data, and then get the value from the execution place. This is a general idea
  */
  setup(){
    return {
      title:'JImmy'
    }
  }
}) 

app.mount('app')

summary

After reading here, you can well understand what createApp did during this period. The receipt is still very large for me

I believe you understand this. If the interviewer can answer this question, the interviewer will be very satisfied!

Keywords: Vue

Added by fert on Mon, 17 Jan 2022 00:09:29 +0200