“This is the 26th day of my participation in the First Challenge 2022. For details: First Challenge 2022.”

Previously on & Background

The process of statically marking the AST obtained by parse is described in detail above. The point of this process is that the AST nodes are statically marked and will not be re-rendered when the data is updated. The core implementation is in the Optimize method:

  1. callgenStaticKeysCachedTo obtainisStaticKeysMethod standby;
  2. callmarkStaticMethod recursive processingastNodes and their children and conditional render nodes, set for each nodestaticProperty with a value ofisStatic()Method return value,isStaticThe method is based onastDetermine whether the information on the node object is static;
  3. callmarkStaticRoot()Check whether the node is a static root. The static root node will be ignored during data update and will not bepatch

Generate the ast to generate the code body of the render function. Code is an object, and the render method is the code generated by converting the AST to generate.

Render is the body of the render function, which we’ll discuss in detail in the following sections:

// This code is the result of the generate method above
code = {
    render: "with(this){return _c('div',{attrs:{\"id\":\"app\"}},[_v(\"\\n\\t\"+_s(msg)+\"\\n\\t\"),_c('some-com',{attrs:{\"some-key\":forProp}}),_v(\"  \"),_c('div',[_v(\"someComputed = \"+_s(someComputed))]),_v(\" \ "), _c (' div '{staticClass: \ "static - div \}", [_v (\ \ "" static node)])], 1)}"

    staticRenderFns: [], (prototype > : {... }}Copy the code

Second, the generate

Methods location: SRC/compiler/codegen/index. The js – > function to generate

Method parameters:

  1. ast, expected to turn intorenderFunction of theastNode object;
  2. compilerOptions: compiler option object

Methods:

  1. throughCodegenStateClass with incomingoptionsgeneratestateObject;
  2. And then callgenElement(ast, state)getrenderFunction body;
  3. Finally returns an object containingrenderstaticRenderFnsProperties,renderIs afterwith(this)Statement wrappedrenderFunction body;
export function generate (
  ast: ASTElement | void,
  options: CompilerOptions
) :CodegenResult {
  // Create CodeGenState instance,
  // CodegenState initializes properties such as staticRenderFns
  const state = new CodegenState(options)

  // Generate string format code such as '_c(tag, data, children, normalizationType)'
  // fix #11483, Root level <script> tags should not be rendered.
  const code = ast ? (ast.tag === 'script' ? 'null' : genElement(ast, state)) : '_c("div")'
  return {
    render: `with(this){return ${code}} `.staticRenderFns: state.staticRenderFns
  }
}
Copy the code

2.1 CodegenState class

Class: the location of the SRC/compiler/codegen/index. The js – > class CodegenState

The constructor argument, Options, is the baseOptions received by the createCompiler(baseOptions) method

Class functions:

  1. The cachebaseOptionsthis.options;
  2. fromoptions.modeulesTo extracttransformCode.genDataMethods, these are the two methods that we talked about earlierparseUsed when thepreTransformNodepostTransformNodeAs well astransformNodeBe of the same origin;options.modulesContains three modules:klass/style/model, includingklass/styleDerived bygenDataMethod, soThis. genDataFns = [klass genData method, style genData method];
  3. implementationVueThe reuse sum of basic instruction processing methods inoptions.directivesFinally all instructions will be extended to a new object and mounted tothis.directives
    • 3.1 Processing basic instructionsV - on, v - bindThe method of
    • 3.2 options.directivesA processing instructionV-model, V-text, V-HTMLThe method of
  4. Initialization judgmentastMethod of whether a node is a componentthis.maybeComponent, its judgment principle isel.componentProperties fortrue, or not platform reserved tags;
  5. Initialize thestaticRenderFns,preAttributes such as
export class CodegenState {
  options: CompilerOptions;
  warn: Function;
  transforms: Array<TransformFunction>;
  dataGenFns: Array<DataGenFunction>;
  directives: { [key: string]: DirectiveFunction };
  maybeComponent: (el: ASTElement) = > boolean;
  onceId: number;
  staticRenderFns: Array<string>;
  pre: boolean;

  constructor (options: CompilerOptions) {
    this.options = options
    this.warn = options.warn || baseWarn
    // Extracts the transformCode method from options.modules, but klass, style, and Model do not export this method
    this.transforms = pluckModuleFunction(options.modules, 'transformCode')
    
    // style/klass exports the genData method
    this.dataGenFns = pluckModuleFunction(options.modules, 'genData') 
    this.directives = extend(extend({}, baseDirectives), options.directives)
    const isReservedTag = options.isReservedTag || no
    this.maybeComponent = (el: ASTElement) = >!!!!! el.component || ! isReservedTag(el.tag)this.onceId = 0
    this.staticRenderFns = []
    this.pre = false}}Copy the code

2.2 genElement

Methods location: SRC/compiler/codegen/index. The js – > function genElement

Method parameters:

  1. astTo generate the rendering functionastNode object;
  2. state.CodegenStateThe instance

Call different processing functions according to different situations, and finally get the rendering tool function call string to achieve the corresponding instruction or component function, for example, v-for will become _L () method call, as shown in the following:

  1. ifelNot the root node, processingel.preAttribute, judgmentelIs there av-preTo command or be in possession ofv-preElement wrapping of instruction;
  2. el.staticRootProperties fortruecallgenStatic()Method to handle the static root node, save the render function of the static root node tostaticRenderFnsAttribute;
  3. el.onceProperties fortrueWhen dealing withv-onceInstruction, callgenOnce()Methods to deal withv-onceInstruction;
  4. el.forAttribute values are specifiedastThere is av-forInstruction, callgenFor()Methods to deal withv-forInstruction;
  5. el.ifProperty value exists, callgenIf()To deal withv-if;
  6. If the current node label istemplateAnd is notslotorv-preThe callgenChildrenProcess child nodes;
  7. If it isslotSlot is calledgenSlot()To deal withslotSlot;
  8. Called if it is a normal element, component, or dynamic componentgenComponent()Processing directlycode; Otherwise see if it is a component (! el.plain) or are there anyv-preAnd is a componentgenData()Process all the attributes on the node, and getdataObject; Then the child nodes are processed;
  9. After the previous operationcodeCode string and then calltransformsFrom the frontoptions.modulesExtract it and mount it toCodegenStateThe instance
export function genElement (el: ASTElement, state: CodegenState) :string {
  if (el.parent) {
    el.pre = el.pre || el.parent.pre
  }

  if(el.staticRoot && ! el.staticProcessed) {// Process the static root node, generate the render function of the static root node, save the result to the staticRenderFns array
    GenStatic returns a string like _m(idx, true)
    return genStatic(el, state)
  } else if(el.once && ! el.onceProcessed) {// Process the node with the v-once instruction, the result will be three:
    return genOnce(el, state)
  } else if(el.for && ! el.forProcessed) {// Handle the v-for instruction on the node,
    _l(exp, function (alias, iterator1, iterator2) {return _c(tag, data, children)})
    // _l is a utility method that renders a list
   
    return genFor(el, state)
  } else if(el.if && ! el.ifProcessed) {// process a node with a v-if instruction to get a ternary expression: condition? render1 : render2
    // condition is the condition, return render function 1 if true, otherwise 2
    return genIf(el, state)
  } else if (el.tag === 'template'&&! el.slotTarget && ! state.pre) {// The current node is not a template tag && is not a slot && does not have a V-pre directive
    // Render all the child nodes, return an array, each array is a child node,
    // Format such as [_c(tag, data, children, normalizationType),...
    return genChildren(el, state) || 'void 0'
  } else if (el.tag === 'slot') {
    // Generate a slot rendering function. _t is a tool method for handling slot
    // _t(slotName, children, attrs, bind)
   
    return genSlot(el, state)
  } else {
    // Handle dynamic components, normal HTML elements (custom components, native tags)
    // component or element
    let code
    if (el.component) {
      code = genComponent(el.component, el, state)
    } else {
      let data
      if(! el.plain || (el.pre && state.maybeComponent(el))) {// Non-normal elements or components with v-pre instructions,
        // Process all attributes of the node and return a JSON string of the form:
        Key: xx, ref: xx,.... } '
        data = genData(el, state)
      }

      // Process the child nodes and get an array of string code for all the child nodes, like this:
      // `['_c(tag, data, children)', ....] , normalizationType`
     
      const children = el.inlineTemplate ? null : genChildren(el, state, true)

      // Get the final string format code, like this:
      // '_c(tag, data, children, normalizationType)'
      code = `_c('${el.tag}'${
        data ? `,${data}` : ' ' // data
      }${
        children ? `,${children}` : ' ' // children
      }) `
    }

    // Call the transformCode method extracted from options.modules via pluckModuleFunction to process the code
    // Klass /style/model in options.mdoules does not export the transformCode method
    // So this loop will not execute, code is the same as the previous code
    for (let i = 0; i < state.transforms.length; i++) {
      code = state.transforms[i](el, code)
    }
    return code
  }
}
Copy the code

Tip: _c, _L, and _t are aliases for render helper functions. _c is the create element, _L is the render list (v-for implementation), and _t is the slot handler.

Four,

This essay begins with another very important topic of the mount phase — generating the body of the render function code.

The previous parse converts the HTML template into an AST that contains all the information for wrapping instructions such as V-IF conditional rendering, V-for list rendering, and so on. Generate is then the process of implementing these instructions using the helper function of the render function. There are two major steps:

  1. instantiationCodegenStateObject, prepare some properties and methods for later creationrenderFunction body standby;
  2. callgenElementCase by caseastGrammar,astBecomes the corresponding help function call;

Generate is an intermediate step in converting Vue template syntax into actual HTML code. This step is not HTML, but JS code, which when executed gets real HTML.