vue3 compile系列三:codegen

711 阅读1分钟

代码生成阶段最后会生成一个字符串,然后用new Function将其转换为render函数。

生成上下文

  1. createCodegenContext(ast, options)生成context上下文,并初始化,给出helper、push、indent、deindent、newLine等方法的实现。
    • helper:返回packages/compiler-core/src/runtimeHelpers.ts中helperNameMap对应的值
    • push:context.code追加(第一个参数);更新游标位置;如果第二个参数存在,建立原位置和新位置的映射
    • indent:换行并且缩进context.indentLevel,context.indentLevel加1
    • deindent:(是否换行,根据参数决定)context.indentLevel减1
    • newLine:换行并且缩进context.indentLevel * 2个空格
  2. 如果options中定义了onContextCreated方法,则调用onContextCreated(context);

preambles

如果是setup() inline模式,preambleContext重新用createCodegenContext(ast, options)赋值;否则,用context赋值。

  • 非浏览器的"module"模式,genModulePreamble(ast, preambleContext, genScopeId, isSetupInlined) --> genImports、genHoists;
  • 否则,genFunctionPreamble(ast, preambleContext) --> helpers中的方法、genHoists。 二者主要区别
  • 生成的preamble中,导入导出使用import/export和require/return
  • _ctx.xx和with(this){xx}

最终生成的就是export function render之前的代码

binding optimizations

const optimizeSources =
    options.bindingMetadata && !options.inline
      ? `, $props, $setup, $data, $options`
      : ``

也就是我们经常见到的

enter render function

构造render函数,其中比较关键的两步

  • genAssets(ast.components, 'component', context)、genAssets(ast.directives, 'directive', context)生成component、directive解析表达式
  • 递归genNode(ast.codegenNode, context)生成VNode结点。根据不同的type,调用不同的方法,也就是我们看到的createVNode、createCommentVNode、createBlock、openBlock、toDisplayString等。

这样,就把ast转换成了render函数字符串。