代码生成阶段最后会生成一个字符串,然后用new Function将其转换为render函数。
生成上下文
- 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个空格
- 如果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函数字符串。