export function generate(
  ast: RootNode,
  options: CodegenOptions & {
    onContextCreated?: (context: CodegenContext) => void
  } = {}
): CodegenResult {
  // enter render function
  const functionName = ssr ? `ssrRender` : `render` // 生成的函数名字
  const args = ssr ? ['_ctx', '_push', '_parent', '_attrs'] : ['_ctx', '_cache'] // 生成的函数参数
  if (!__BROWSER__ && options.bindingMetadata && !options.inline) {
    // binding optimization args
    args.push('$props', '$setup', '$data', '$options') // 添加参数
  }
  const signature =
    !__BROWSER__ && options.isTS
      ? args.map(arg => `${arg}: any`).join(',')
      : args.join(', ')

  if (genScopeId && !isSetupInlined) {
    // root-level _withId wrapping is no longer necessary after 3.0.8 and is
    // a noop, it's only kept so that code compiled with 3.0.8+ can run with
    // runtime < 3.0.8.
    // TODO: consider removing in 3.1
    push(`const ${functionName} = ${PURE_ANNOTATION}${WITH_ID}(`)
  }
  if (isSetupInlined || genScopeId) {
    push(`(${signature}) => {`)
  } else {
    // 生成 function render (...args) {}
    push(`function ${functionName}(${signature}) {`)
  }
  indent()

  if (useWithBlock) {
    // 通过with进行包装,这样template内就不需要去写this,就可以直接拿到setup的值
    push(`with (_ctx) {`) 
    indent()
    // function mode const declarations should be inside with block
    // also they should be renamed to avoid collision with user properties
    if (hasHelpers) {
      /**
       *  调用内置的帮助函数生成语句,一个生成的例子
       *  
          const { 
            toDisplayString as _toDisplayString, 
            createVNode as _createVNode, 
            vModelText as _vModelText, 
            withDirectives as _withDirectives, 
            resolveComponent as _resolveComponent, 
            renderList as _renderList, 
            Fragment as _Fragment, 
            openBlock as _openBlock, 
            createBlock as _createBlock, 
            Suspense as _Suspense, 
            withCtx as _withCtx, 
            Teleport as _Teleport 
          } = _Vue
      */
      push(
        `const { ${ast.helpers
          .map(s => `${helperNameMap[s]}: _${helperNameMap[s]}`)
          .join(', ')} } = _Vue`
      )
      push(`\n`)
      newline()
    }
  }

  //生成组件
  if (ast.components.length) {
    genAssets(ast.components, 'component', context)
    if (ast.directives.length || ast.temps > 0) {
      newline()
    }
  }
  // 生成指令
  if (ast.directives.length) {
    genAssets(ast.directives, 'directive', context)
    if (ast.temps > 0) {
      newline()
    }
  }

  if (ast.temps > 0) {
    push(`let `)
    for (let i = 0; i < ast.temps; i++) {
      push(`${i > 0 ? `, ` : ``}_temp${i}`)
    }
  }
  if (ast.components.length || ast.directives.length || ast.temps) {
    push(`\n`)
    newline()
  }

  // 生成 VNode tree 表达式
  if (!ssr) {
    push(`return `)
  }

  // 调用在转换期间生成的coegenNode,传入genNode,并在内部通过createVnode进行生成
  if (ast.codegenNode) {
    genNode(ast.codegenNode, context)
  } else {
    push(`null`)
  }

  if (useWithBlock) {
    deindent()
    push(`}`)
  }

  deindent()
  push(`}`)

  if (genScopeId && !isSetupInlined) {
    push(`)`)
  }

  // 返回生成的结果
  return {
    ast,
    code: context.code,
    preamble: isSetupInlined ? preambleContext.code : ``,
    // SourceMapGenerator does have toJSON() method but it's not in the types
    map: context.map ? (context.map as any).toJSON() : undefined
  }
}

总结

至此模板编译的过程就到此结束了,下一篇来看下生成的代码如何转换成render function