preface

The first two articles focused on parsing and optimizing the VUE compiler:

  • Parse the COMPONENT’s HTML template into an AST object
  • Static marking is performed based on AST syntax tree. First, whether each node is a static node is marked, and then the static root node is further marked so that the update of the static root node can be skipped in subsequent updates to improve performance

Let’s take a look at how the VUE compiler generates run rendering functions from the AST syntax tree.

Deep source

CreateCompiler () method – entry

File Location:/src/compiler/index.js

Chief among them is the generate(AST, options) method, which is responsible for generating render functions from the AST syntax tree.

/* All the work up to this point was just to build platform-specific compilation options, For example, web platform 1, parse HTML template into AST 2, statically mark ast tree 3, generate ast render function - static render function into code.staticrenderfns array - dynamic render function code.render - Vnode */ can be obtained by executing the render function during future rendering
export const createCompiler = createCompilerCreator(function baseCompile(template: string, options: CompilerOptions) :CompiledResult {
  The AST object of each node sets all the information about the element, such as tag information, attribute information, slot information, parent node, child node, etc. */
  const ast = parse(template.trim(), options)

  /* Optimize, iterate over AST, statically mark each node - mark each node as a static node and ensure that these static nodes are skipped in subsequent updates - mark static root nodes for the render function generation stage, optimize the render function that generates static root nodes, iterate over AST, statically mark each node */
  if(options.optimize ! = =false) {
    optimize(ast, options)
  }

  /* Generate render functions from the AST syntax tree like: code.render = "_c('div',{attrs:{"id":"app"}},_l((arr),function(item){return _c('div',{key:item},[_v(_s(item))])}),0)" */
  const code = generate(ast, options)

  return {
    ast,
    render: code.render,
    staticRenderFns: code.staticRenderFns
  }
})
Copy the code

The generate () method

File Location:src\compiler\codegen\index.js

When code is assigned, the main content is generated by the genElement(ast, state) method.

/* Generate render functions from AST: -render as string code -staticrenderfns as multiple string code of the form 'with(this){return XXX}' */
export function generate (
  ast: ASTElement | void./ / ast objects
  options: CompilerOptions // Compile options
) :CodegenResult {

  /* Instantiate the CodegenState object, taking the compile option to get state, which has most of the same properties as options */
  const state = new CodegenState(options)

  /* Generates string format code such as: '_c(tag, data, children, normalizationType)' - data forms JSON strings for attributes on nodes such as '{key: xx, ref: xx,... }' -children is an array of string codes for all child nodes in the format of '['_c(tag, data, children)',... NormalizationType 'and -normalization is the fourth parameter of _C, which means the normalization type of the node. Note: Code does not have to be _c, but it could be something else, such as _m(0) */ if the entire component is static
  const code = ast ? (ast.tag === 'script' ? 'null' : genElement(ast, state)) : '_c("div")'

  return {
    render: `with(this){return ${code}} `.staticRenderFns: state.staticRenderFns
  }
}
Copy the code

GenElement () method

File Location:src\compiler\codegen\index.js

export function genElement (el: ASTElement, state: CodegenState) :string {
  if (el.parent) {
    el.pre = el.pre || el.parent.pre
  }

  if(el.staticRoot && ! el.staticProcessed) {1. Place the current static node's render function into the array staticRenderFns. 2. Return an executable function _m(idx, true or ") */
    return genStatic(el, state)

  } else if(el.once && ! el.onceProcessed) {/* If (condition, condition, condition); /* If (condition, condition, condition, condition); render1 : Render2 '2 is a static node contained within the V-for directive, resulting in _O (_c(tag, data, children), number, key)'. Get '_m(idx, true of' ") */
    return genOnce(el, state)

  } else if(el.for && ! el.forProcessed) {_l(exp, function(alias, iterator1, iterator2){return _c(tag, data, children)}) '*/ 
    return genFor(el, state)

  } else if(el.if && ! el.ifProcessed) {/* Process a node with a V-if instruction, resulting in a ternary expression: 'condition? render1 : render2` */
    return genIf(el, state)

  } else if (el.tag === 'template'&&! el.slotTarget && ! state.pre) {/* When the current node is a template tag and not a slot and node with v-pre instructions, go here to generate the render function for all the child nodes, and return an array of the format:  `[_c(tag, data, children, normalizationType), ...] ` * /
    return genChildren(el, state) || 'void 0'

  } else if (el.tag === 'slot') {

    /* Generate the slot rendering function, and get: '_t(slotName, children, attrs, bind)' */
    return genSlot(el, state)

  } else {
    /* Component or element handles both dynamic components and common elements (custom components, native tags, platform-reserved tags, such as every HTML tag in a Web platform) */

    let code
    if (el.component) {
      _c(compName, data, children) */
      code = genComponent(el.component, el, state)

    } else {
      // Handle common elements (custom components, native tags)

      let data
      if(! el.plain || (el.pre && state.maybeComponent(el))) {/* Non-ordinary elements or components with v-pre instructions go here, process all attributes of the node, and return a JSON string, such as: '{key: xx, ref: xx,... } '* /
        data = genData(el, state)
      }

      ['_c(tag, data, children)', ['_c(tag, data, children)',... NormalizationType ', where the normalization type of the normalization node is omitted */
      const children = el.inlineTemplate ? null : genChildren(el, state, true)

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

    }

    /* If the transformCode method is provided, the final code is processed by this method in each module. The framework does not provide this method, but even if it does, The final format is also _C (tag, data, children) module transforms */
    for (let i = 0; i < state.transforms.length; i++) {
      code = state.transforms[i](el, code)
    }

    / / return code
    return code
  }
}
Copy the code

GenChildren () method

File Location:src\compiler\codegen\index.js

/* Generate a render function for all child nodes and return an array of the format '[_c(tag, data, children, normalizationType),... ` * /
export function genChildren (el: ASTElement, state: CodegenState, checkSkip? : boolean, altGenElement? :Function, altGenNode? :Function
) :string | void {

 // Get all child nodes
  const children = el.children

  if (children.length) {
    // First child node
    const el: any = children[0]

    // optimize single v-for
    if (children.length === 1&& el.for && el.tag ! = ='template'&& el.tag ! = ='slot'
    ) {
      /* Optimization: - Condition: only one child && has a V-for instruction on the child && tags are not template or slot - mode: Call genElement directly to generate the render function for that node, without going through the loop and calling genCode to get the render function */
      const normalizationType = checkSkip
        ? state.maybeComponent(el) ? ` `, 1 : ` `, 0
        : ` `
      return `${(altGenElement || genElement)(el, state)}${normalizationType}`
    }

    // Get node normalized type, return number: 0, 1, 2
    const normalizationType = checkSkip
      ? getNormalizationType(children, state.maybeComponent)
      : 0

    // is a function that generates code
    const gen = altGenNode || genNode

    /* Return an array in which each element is a child node render function format: ['_c(tag, data, children, normalizationType)',...] * / 
    return ` [${children.map(c => gen(c, state)).join(', ')}]${
      normalizationType ? `,${normalizationType}` : ' '
    }`}}Copy the code

GenNode () method

File Location:src\compiler\codegen\index.js

function genNode (node: ASTNode, state: CodegenState) :string {
  // Handle normal element nodes
  if (node.type === 1) {
    return genElement(node, state)
  } else if (node.type === 3 && node.isComment) {
    // Process text comment nodes
    return genComment(node)
  } else {
    // Process text nodes
    return genText(node)
  }
}
Copy the code

GenComment () method

File Location:src\compiler\codegen\index.js

// Returns the value in the format '_e(XXXX)'
export function genComment (comment: ASTText) :string {
  return `_e(The ${JSON.stringify(comment.text)}) `
}
Copy the code

GenText () method

File Location:src\compiler\codegen\index.js

// Get the return value in the format of '_v(XXXXX)'
export function genText (text: ASTText | ASTExpression) :string {
  return `_v(${text.type === 2
    ? text.expression // no need for () because already wrapped in _s()
    : transformSpecialNewlines(JSON.stringify(text.text))
  }) `
}
Copy the code

GenData () method

File Location:src\compiler\codegen\index.js

/* Process a number of attributes on a node and generate a JSON string consisting of these attributes, such as data = {key: xx, ref: xx,... } * /
export function genData(el: ASTElement, state: CodegenState) :string {

  // A JSON string composed of the attributes of the node
  let data = '{'

  /* Handle the instructions first, since the instructions may change those attributes to execute the instruction compilation method before generating other attributes, such as v-text, V-html, v-model for the Web platform, and then add the corresponding attributes to the EL object, such as V-text: El.textcontent = _S (value, dir) V-html: el.innerhtml = _S (value, dir) When the directive still has tasks at run, such as V-model, return directives: cache [{ name, rawName, value, arg, modifiers }, ...}] */
  const dirs = genDirectives(el, state)

  if (dirs) data += dirs + ', '

  // key, data = {key: XXX}
  if (el.key) {
    data += `key:${el.key}, `
  }
  // data = {ref: XXX}
  if (el.ref) {
    data += `ref:${el.ref}, `
  }
  // The node with ref attribute is inside the node with v-for instruction, data = {refInFor: true}
  if (el.refInFor) {
    data += `refInFor:true,`
  }
  // data = {pre: true}
  if (el.pre) {
    data += `pre:true,`
  }
  
      
       , data = {tag: 'component'}
      
  if (el.component) {
    data += `tag:"${el.tag}", `
  }
  /* staticClass: xx, class: xx, staticStyle: xx, style: xx } module data generation functions */
  for (let i = 0; i < state.dataGenFns.length; i++) {
    data += state.dataGenFns[i](el)
  }
  /* Other attributes, get data = {attrs: static attribute string} or data = {attrs: '_d(static attribute string, dynamic attribute string)'} attributes */
  if (el.attrs) {
    data += `attrs:${genProps(el.attrs)}, `
  }
  // DOM props, the result is the same as el. Attrs
  if (el.props) {
    data += `domProps:${genProps(el.props)}, `
  }
  -data = {' on${eventName}:handleCode '} or - {' on_d(${eventName}:handleCode ', `${eventName},handleCode`) } event handlers */
  if (el.events) {
    data += `${genHandlers(el.events, false)}, `
  }
  /* Events with the.native modifier, -data = {' nativeOn${eventName}:handleCode '} or - {' nativeOn_d(${eventName}:handleCode ', `${eventName},handleCode`) */
  if (el.nativeEvents) {
    data += `${genHandlers(el.nativeEvents, true)}, `
  }
  /* Non-scoped slots, data = {slot: slotName} slot target only for non-scoped slots */
  if(el.slotTarget && ! el.slotScope) { data +=`slot:${el.slotTarget}, `
  }
  // scoped slots, data = {scopedSlots: '_u(XXX)'}
  if (el.scopedSlots) {
    data += `${genScopedSlots(el, el.scopedSlots, state)}, `
  }
  /* Data = {model: {value, callback, expression}} component V-model */
  if (el.model) {
    data += `model:{value:${el.model.value },callback:${el.model.callback },expression:${el.model.expression }}, `
  }
  /* Inline-template: data = {inlineTemplate: {render: function() {render: function}, staticRenderFns: [ function() {}, ... ] }} * /
  if (el.inlineTemplate) {
    const inlineTemplate = genInlineTemplate(el, state)
    if (inlineTemplate) {
      data += `${inlineTemplate}, `}}// Delete the last comma of the JSON string, and add the closing parentheses.
  data = data.replace($/ /,.' ') + '} '
  
  /* V-bind dynamic argument wraparound must use the same V-bind object to apply the dynamic binding argument to merge auxiliary objects in order to properly handle the class/style/mustUseProp properties. * /
  if (el.dynamicAttrs) {
    data = `_b(${data},"${el.tag}",${genProps(el.dynamicAttrs)}) `
  }
  // v-bind data wrap
  if (el.wrapData) {
    data = el.wrapData(data)
  }
  // v-on data wrap
  if (el.wrapListeners) {
    data = el.wrapListeners(data)
  }
  return data
}
Copy the code

GenDirectives () method

File Location:src\compiler\codegen\index.js

Cache: [{name, rawName, value, arg, modiFIERS},...}] */ Directives are returned if there is a runtime task
function genDirectives(el: ASTElement, state: CodegenState) :string | void {
  // Get the instruction array
  const dirs = el.directives
  // There is no command
  if(! dirs)return

  // The processing result of the instruction
  let res = 'directives:['
  // Is used to indicate whether the directive needs to complete tasks at run time, such as the INPUT event of the V-model
  let hasRuntime = false
  let i, l, dir, needRuntime

  // Iterate over the instruction array
  for (i = 0, l = dirs.length; i < l; i++) {
    dir = dirs[i]
    needRuntime = true
    // Get the processing method of the node's current instruction, such as v-html, V-text, V-model for the Web platform
    const gen: DirectiveFunction = state.directives[dir.name]
    if (gen) {
      // Execute the compilation method of the instruction, and return true if the instruction still needs to complete part of the task at runtime, such as v-modelneedRuntime = !! gen(el, dir, state.warn) }if (needRuntime) {
      // indicates that the directive has tasks at run time
      hasRuntime = true
       // res = directives:[{ name, rawName, value, arg, modifiers }, ...]
      res += `{name:"${dir.name}",rawName:"${dir.rawName}"${dir.value ? `,value:(${dir.value}),expression:The ${JSON.stringify(dir.value)}` : ' '
        }${dir.arg ? `,arg:${dir.isDynamicArg ? dir.arg : `"${dir.arg}"`}` : ' '
        }${dir.modifiers ? `,modifiers:The ${JSON.stringify(dir.modifiers)}` : ' '
        }}, `}}// Res is returned only if the directive has a run-time task
  if (hasRuntime) {
    return res.slice(0, -1) + '] '}}Copy the code

GenDirectives () method

File Location:src\compiler\codegen\index.js

/* If there is no dynamic attribute, return: 'attrName,attrVal,... 'If dynamic property exists, return: '_d(static property string, dynamic property string)' */
function genProps(props: Array<ASTAttr>) :string {
  // Static attributes
  let staticProps = ` `
  // Dynamic attributes
  let dynamicProps = ` `

  // Iterate over the property array
  for (let i = 0; i < props.length; i++) {
    / / property
    const prop = props[i]
    / / property values
    const value = __WEEX__
      ? generateValue(prop.value)
      : transformSpecialNewlines(prop.value)

    if (prop.dynamic) {
       // Dynamic properties, 'dAttrName,dAttrVal... `
      dynamicProps += `${prop.name}.${value}, `
    } else {
      // Static attribute, 'attrName:attrVal,... '
      staticProps += `"${prop.name}":${value}, `}}// Close the static attribute string and remove the ',' at the end of the static attribute.
  staticProps = ` {${staticProps.slice(0, -1)}} `

  if (dynamicProps) {
    // Return _d(static attribute string, dynamic attribute string)
    return `_d(${staticProps}[${dynamicProps.slice(0, -1)}]) `
  } else {
    // Indicates that there is no dynamic attribute in the property array
    return staticProps
  }
}
Copy the code

GenHandlers () method

File Location:src\compiler\codegen\events.js

/ * generate custom event code dynamic: 'nativeOn | on_d (staticHandlers, [dynamicHandlers])' static: ` nativeOn | on ${staticHandlers} ` * /
export function genHandlers (events: ASTElementHandlers, isNative: boolean) :string {
  // Native is nativeOn, otherwise on
  const prefix = isNative ? 'nativeOn:' : 'on:'
  / / static
  let staticHandlers = ` `
  / / dynamic
  let dynamicHandlers = ` `
  Events = [{name: {value: callback function name,...}}] */ 
  for (const name in events) {
    const handlerCode = genHandler(events[name])
    if (events[name] && events[name].dynamic) {
      // dynamic, dynamicHandles = 'eventName,handleCode,... , `
      dynamicHandlers += `${name}.${handlerCode}, `
    } else {
      // staticHandlers = `eventName:handleCode,... , `
      staticHandlers += `"${name}":${handlerCode}, `}}// Close the static event-handling code string, removing the trailing ','
  staticHandlers = ` {${staticHandlers.slice(0, -1)}} `

  if (dynamicHandlers) {
    // Dynamic, on_d(statickHandles, [dynamicHandlers])
    return prefix + `_d(${staticHandlers}[${dynamicHandlers.slice(0, -1)}]) `
  } else {
    // Static, 'on${staticHandlers}'
    return prefix + staticHandlers
  }
}
Copy the code

GenStatic () method

File Location:src\compiler\codegen\index.js

Hoist static sub-trees out */ hoist static sub-trees out */ static sub-trees out */
function genStatic(el: ASTElement, state: CodegenState) :string {
  // Indicates that the current static node has been processed
  el.staticProcessed = true

  /* Some elements (templates) need to behave differently in the V-pre node. All pre nodes are static roots, so they can be used to wrap state changes and reset them when exiting the Pre node. */
  const originalPreState = state.pre
  if (el.pre) {
    state.pre = el.pre
  }

  /* Push the static root render function into the staticRenderFns array, for example: [' with(this){return _c(tag, data, children)} '] */
  state.staticRenderFns.push(`with(this){return ${genElement(el, state)}} `)

  state.pre = originalPreState
  /* Returns an executable function: _m(idx, true or ") idx = Subscript */ of the current static node's rendering function in the staticRenderFns array
  return `_m(${state.staticRenderFns.length - 1
    }${el.staticInFor ? ',true' : ' '
    }) `
}
Copy the code

GenOnce () method

File Location:src\compiler\codegen\index.js

/* If (condition, condition, condition) {if (condition, condition); /* If (condition, condition, condition); render1 : Render2 2, the current node is a static node contained in the V-for directive, resulting in _O (_c(tag, data, children), number, key) '3, the current node is a pure V-once node, Get '_m(idx, true of' ") 'v-once */
function genOnce(el: ASTElement, state: CodegenState) :string {
  // The v-once directive marking the current node has already been processed
  el.onceProcessed = true
  if(el.if && ! el.ifProcessed) {/* If the v-if instruction &&if instruction has not been processed, then the node with the V-if instruction is processed, resulting in a ternary expression: condition? render1 : render2 */ 
    return genIf(el, state)

  } else if (el.staticInFor) {
    /* Indicates that the current node is wrapped in a static node that also contains the v-for instruction key */
    let key = ' '
    let parent = el.parent
    while (parent) {
      if (parent.for) {
        key = parent.key
        break
      }
      parent = parent.parent
    }

    // If the key does not exist, the v-once node can only be used inside the V-for node with the key
    if(! key) { process.env.NODE_ENV ! = ='production' && state.warn(
        `v-once can only be used inside v-for that is keyed. `,
        el.rawAttrsMap['v-once'])return genElement(el, state)
    }

    // Generate _o(_c(tag, data, children), number, key) '
    return `_o(${genElement(el, state)}.${state.onceId++}.${key}) `
  } else {
     _m(idx, true or "") */ 
    return genStatic(el, state)
  }
}
Copy the code

GenFor () method

File Location:src\compiler\codegen\index.js

_l(exp, function(alias, iterator1, iterator2){return _c(tag, data, children)}) '*/
export function genFor(el: any, state: CodegenState, altGen? :Function, altHelper? : string) :string {
  // An iterator for v-for, such as an array
  const exp = el.for
  // Alias for iteration
  const alias = el.alias
  // iterator v-for = "(item,idx) in obj", such as iterator1 = idx
  const iterator1 = el.iterator1 ? `,${el.iterator1}` : ' '
  const iterator2 = el.iterator2 ? `,${el.iterator2}` : ' '

  // the v-for directive must use key when on the component
  if(process.env.NODE_ENV ! = ='production'&& state.maybeComponent(el) && el.tag ! = ='slot'&& el.tag ! = ='template' &&
    !el.key
  ) {
    state.warn(
      ` <${el.tag} v-for="${alias} in ${exp}">: component lists rendered with ` +
      `v-for should have explicit keys. ` +
      `See https://vuejs.org/guide/list.html#key for more info.`,
      el.rawAttrsMap['v-for'].true /* tip */)}// indicates that the v-for directive on the current node has been processed
  el.forProcessed = true // avoid recursion

  // return 'exp (alias, iterator1, iterator2){return _c(tag, data, children)})'
  return `${altHelper || '_l'}((${exp}), ` +
    `function(${alias}${iterator1}${iterator2}) {` +
    `return ${(altGen || genElement)(el, state)}` +
    '}) '
}
Copy the code

GenIf () method

File Location:src\compiler\codegen\index.js

// Process a node with a V-if instruction, resulting in a ternary expression, condition? render1 : render2
export function genIf(el: any, state: CodegenState, altGen? :Function, altEmpty? : string) :string {
  // The v-if directive that marks the current node has already been processed to avoid invalid recursion
  el.ifProcessed = true // avoid recursion
  // Get the ternary expression, condition? render1 : render2
  return genIfConditions(el.ifConditions.slice(), state, altGen, altEmpty)
}

function genIfConditions(conditions: ASTIfConditions, state: CodegenState, altGen? :Function, altEmpty? : string) :string {

  // If the length is empty, an empty node rendering function is returned
  if(! conditions.length) {return altEmpty || '_e()'
  }

  // Take the first condition object from the conditions array {exp, block}
  const condition = conditions.shift()
  // The result is a ternary expression string, condition? Render function 1: Render function 2
  if (condition.exp) {
    /* If condition. Exp is true, a ternary expression is obtained; if not, the next element in the array is recursively found until the condition is found, and a ternary expression */ is returned
    return ` (${condition.exp})?${genTernaryExp(condition.block) }:${genIfConditions(conditions, state, altGen, altEmpty) }`
  } else {
    return `${genTernaryExp(condition.block)}`
  }

  // v-if with v-once should generate code like (a)? _m(0):_m(1)
  function genTernaryExp(el) {
    return altGen
      ? altGen(el, state)
      : el.once
        ? genOnce(el, state)
        : genElement(el, state)
  }
}
Copy the code

GenIf () method

File Location:src\compiler\codegen\index.js

_t(slotName, children, attrs, bind) */
function genSlot(el: ASTElement, state: CodegenState) :string {
   // Slot name
  const slotName = el.slotName || '"default"'
  // Generate all child nodes
  const children = genChildren(el, state)
  // Result string _t(slotName, children, attrs, bind)
  let res = `_t(${slotName}${children ? `,function(){return ${children}} ` : ' '}`
  
  const attrs = el.attrs || el.dynamicAttrs
    ? genProps((el.attrs || []).concat(el.dynamicAttrs || []).map(attr= > ({
      // slot props are camelized
      name: camelize(attr.name),
      value: attr.value,
      dynamic: attr.dynamic
    })))
    : null

  const bind = el.attrsMap['v-bind']
  
  if((attrs || bind) && ! children) { res +=`,null`
  }
  if (attrs) {
    res += `,${attrs}`
  }
  if (bind) {
    res += `${attrs ? ' ' : ',null'}.${bind}`
  }
  return res + ') '
}
Copy the code

GenComponent () method

File Location:src\compiler\codegen\index.js

/* Generate dynamic component render function, Return '_C (compName, data, children)' componentName is el.component, take it as argument to shun flow's pessimistic refinement */
function genComponent(componentName: string, el: ASTElement, state: CodegenState) :string {
   // All child nodes
  const children = el.inlineTemplate ? null : genChildren(el, state, true)
  // Return '_c(compName, data, children)', where compName is the value of the is attribute
  return `_c(${componentName}.${genData(el, state)}${children ? `,${children}` : ' '
    }) `
}
Copy the code

conclusion

What is the process of generating a render function?

There are two types of renderings generated by the compiler:

  • renderFunction that is responsible for generating dynamic nodesvnode
  • staticRenderFnsIn the arrayStatic rendering functionIs responsible for generating static nodesvnode

_C (tag, attr, children, normalizationType) : _C (tag, attr, children, normalizationType)

  • tagIs the tag name
  • attrIs a property object
  • childrenIs an array of child nodes in which each element is of the format_c(tag, attr, children, normalizationTYpe)In the form of,
  • normalizationRepresents the normalized type of the node, which is a number 0, 1, 2

How are static nodes handled?

The processing of static nodes is divided into two steps:

  • Static nodes will be generatedvnodeFunction instaticRenderFnsIn the array
  • Returns a_m(idx)The executable function of thestaticRenderFnsThe subscript in the array isidxFunction to generate static nodesvnode

How are v-once, V-IF, V-for, components, etc handled?

  • purev-onceNode processing mode andStatic nodeconsistent
  • v-ifThe result of node processing is oneTernary expression
  • v-forThe result of the node’s processing is executable_lFunction, which is responsible for generatingv-forThe node’svnode
  • The result of processing the component is the same as that of a normal element_c(compName)The executable code that generates the componentvnode

The articles

  • What does vUE initialization do?
  • How to understand vUE responsiveness?
  • How does vUE update asynchronously?
  • Do you really understand the Vue global Api?
  • Did you lose the instance method in VUE?
  • Do you know Hook Event?
  • Vue compiler parsing
  • Optimization of vUE compiler parsing