This is the 14th day of my participation in the First Challenge 2022.

Previously on & Background

Since the beginning of this series, we’ve been saying the same thing: The vue.prototype. _init method, which includes merging vue.options with mergeOptions we pass in the option object, initializing the initState method of Vue responsive logic, and so on, starts with the last part of the _init method — mount.

Why mount first?

Strictly speaking, the whole process of real data responsiveness is not complete, because we have only shown how to define data as responsiveness: The defineReactive() method uses the object.defineProperty () method to set the interception of getters and setters for data access and Settings. But to be clear: getters and setters are not triggered immediately after they are defined. Getters are not triggered until they are accessed and setters are not triggered until they are set.

Given the above situation, I don’t want to mix a process that relies on collecting and distributing updates into the initialization of responsive data. Again, I follow the code through to the mount phase.

The mount phase compiles the template to produce the render function, which takes care of template syntax, bind, etc., and turns it into a function call that values values from the VM. This is what we call a render function. The render function is then executed, at which point the previous reading of reactive data is triggered, that is, the getter is fired.

$mount in _init

export function initMixin (Vue: Class<Component>) {

  Vue.prototype._init = function (options? :Object) {
    / /... Init and mergeOptions
    
    // $mount is called
    if (vm.$options.el) {
      vm.$mount(vm.$options.el)
    }
  }
}
Copy the code

If we pass the el attribute in options, the automatic mount will be enabled. If we pass the EL attribute in options, the automatic mount will be enabled. Test.html before us. In our demo the el property value is the string ‘#app’;

In addition, you can see that $mount is a Vue. Prototype method. Let’s see where this method is registered.

$mount method

Since we are using vue.js with a compiler, this version is slightly different from the one without a compiler. So let’s first look at where this method is defined;

$mount ntry-runtime-with-compiler.js () {/ / ntry-runtimewith-compiler.js () {/ / ntry-runtimewith-compiler.js () {/ / ntry-runtimewith-compiler.js () {/ / ntry-runtimewith-compiler.js () {/ / ntry-runtimewith-compiler.js ()

Javascript -> Vue.prototype.$mount

The render function and staticRenderFns () function are generated by compiling the component template with the runtime compiler, and then the VNode is generated by calling the previous Render function at mount time, and then the VNode is converted into a real DOM and inserted into the page to complete the rendering. This is achieved through the following steps:

  1. According to theelOptions forelThe correspondingDOMNode, i.e.,div#app
  2. If you detectvm.$optionsThere is norenderFunction option, gets the template optiontemplate, and then processing different types of templates, and finally processing into a string
  3. Call compilation to compile the template into a rendering function
  4. Put the two render functions invm.$optionsOn, that is,this.$options.renderthis.$options.staticRenderFns
  5. Call the mount method
const mount = Vue.prototype.$mount // Cache the generic $mount method, which contains no compiler logic
Vue.prototype.$mount = function (
  el?: string | Element,
  hydrating?: boolean
) :Component {
  / / the mount point
  el = el && query(el)

  / / configuration items
  const options = this.$options
 
  if(! options.render) {let template = options.template
    if (template) {
      // Process the template option
      if (typeof template === 'string') {
        // { template: '#app' } 
        // When template is an ID selector, get the innerHtml of the element as template
        if (template.charAt(0) = = =The '#') {
          template = idToTemplate(template)
      
        }
      } else if (template.nodeType) {
        // template is a DOM node object, nodeType identifies the HTML nodeType field,
        // Different HTML nodes have different types. We also get their innerHTML
        template = template.innerHTML
      } else {
    
        return this}}else if (el) {
      // If the EL option is set, get the outerHTML of the EL selector as the template
      // new Vue({el: '#app'})
      template = getOuterHTML(el)
    }

    if (template) {

      // Compile the template to get the dynamic and static rendering functions. Render function, also dynamic? Static?
      const { render, staticRenderFns } = compileToFunctions(template, {
        outputSourceRange: process.env.NODE_ENV ! = ='production',
        shouldDecodeNewlines,
        shouldDecodeNewlinesForHref,
        delimiters: options.delimiters, // Delimiter: default {{}}
        comments: options.comments // Whether to keep comments
      }, this)

      // Place two rendering functions on vm.$options, i.e. This.$options,
      // For the vue.prototype. _render method
      options.render = render
      options.staticRenderFns = staticRenderFns
    }
  }
  // Perform the mount
  return mount.call(this, el, hydrating)
}
Copy the code

3.1 Preparing a Template

As you can see from the image above, template is the HTML string we wrote in the div#app section of test.html:

3.2 compileToFunctions Enters the compilation phase

CompileToFunctions are the return value of createCompiler, and createCompiler is the return value of createCompilerCreator, so this is a bit complicated, CompileToFunctions are equivalent to createCompilerCreator()() so we can look at them from behind.

3.2.1 createCompilerCreator method

SRC /compiler/create-compiler.js -> createCompilerCreator

Method parameters: baseCompile, function data type, which is passed in when createCompiler is called when createCompiler is obtained.

export function createCompilerCreator (baseCompile: Function): Function {// This is the createCompiler Function // baseCompile will call the return Function in the createCompiler that returns createCompiler (baseOptions: CompilerOptions) { } }Copy the code

CreateCompilerCreator receives the baseCompile function and returns a factory function. This factory function is the createCompilerCreator function.

3.2.2 createCompiler method

Method position: is the return value of the previous createCompilerCreator method;

Method parameters: baseOptions To create the configuration required by the compiler

export function createCompilerCreator (baseCompile: Function) :Function {
  return function createCompiler (baseOptions: CompilerOptions) {
    function compile (template: string, options? : CompilerOptions) :CompiledResult {
      //....
      return compiled
    }

    // compile processes the compile and returns the result of the compile
    return {
      compile,
      compileToFunctions: createCompileToFunctionFn(compile) // This is called compileToFunctions}}}Copy the code

So, calling createCompiler gives you this object:

return {
  compile,
  compileToFunctions: createCompileToFunctionFn(compile) 
}
Copy the code

All you need in $mount is the compileToFunctions method to which the template is passed and which is the return value of createToFunctionFn.

3.2.3 createToFunctionFn method

Methods location: SRC/compiler/to – function. Js – > function createCompileToFunctionFn return compileToFunctions

Method parameters:

  1. template: template string
  2. options: compiler options
  3. vm:VueThe instance

So after doing all of these things, you realize that this is the function that gets executed, so let’s see what happens here.

Methods:

  1. Receives the compilation options passed inoptions
  2. checkCSP.CSPThe compiler will be affected
  3. Check the cache and return if the cache has compiled results
  4. performcreateCompileToFunctionFnThe receivedcompileFunction compilation,templateoptionsIt’s all passed tocompile
  5. thecompileThe resulting string becomes a function, called a rendering function, of course it has to be a function
// The export function.. That's not the point, it's the return value
export function createCompileToFunctionFn (compile: Function) :Function {
  const cache = Object.create(null)
  // The return value is important
  return function compileToFunctions (template: string, options? : CompilerOptions, vm? : Component) :CompiledFunctionResult {
    // The compiler option passed in
    options = extend({}, options)
    const warn = options.warn || baseWarn
    delete options.warn

   
    / /... CSP is a content security policy that restricts the use of new Function and eval,
    // The compiler will not work without it
 
    // If there is a cache, get the result of the last compilation directly from the cache
    const key = options.delimiters
      ? String(options.delimiters) + template
      : template
    if (cache[key]) {
      return cache[key]
    }

    // execute the compile function to get the result
    const compiled = compile(template, options) / / this is the compile createCompilerCreator call createCompileToFunctionsFn method when the incoming callback, in SRC/compiler/create - compiler. Js

  
    // Check that errors and tips generated during compilation are output to console
    if(process.env.NODE_ENV ! = ='production') {
      // ...
    }


    // Convert the compiled string code to a Function, implemented by new Function(code)
    const res = {}
    const fnGenErrors = []
    res.render = createFunction(compiled.render, fnGenErrors)
    res.staticRenderFns = compiled.staticRenderFns.map(code= > {
      return createFunction(code, fnGenErrors)
    })

    / /...

    // Cache the compiled results and return res
    return (cache[key] = res)
  }
}
Copy the code

This operation matryoshka saw tears, the slot machine saw exclaims complex. I have to admit, though, that I haven’t seen the benefit of this design. The factory-suite factory mode currently ensures that each new function is created, with different and independent rendering functions from each other.

Four,

This essay mainly discusses the following questions:

  1. $mountWhen and where methods are registered;
  2. templateTemplate preparation process, and different types of template processing
  3. Compiled templatecompileToFunctionsMethod of obtaining the path, the doll’s sense of deja vu