肝了4天,终于把Vue3编译原理之transform憋出来了

上一篇主要讲到了在vue中,template通过parse生成ast(抽象语法树)的主要核心流程。这个ast是对模板的完整描述,不能直接拿来生成代码,缺乏语义化,并且没有包含编译优化的相关属性,还需要进一步转换,所以用到了我们今天需要讲解的transform

主要流程

export function transform(root: RootNode, options: TransformOptions) {const context = createTransformContext(root, options)traverseNode(root, context)if (options.hoistStatic) {hoistStatic(root, context)}if (!options.ssr) {createRootCodegen(root, context)}// finalize meta informationroot.helpers = [...context.helpers.keys()]root.components = [...context.components]root.directives = [...context.directives]root.imports = context.importsroot.hoists = context.hoistsroot.temps = context.tempsroot.cached = context.cachedif (__COMPAT__) {root.filters = [...context.filters!]}
} 

首先是创建transform上下文,通过traverseNode遍历ast节点,通过createRootCodegen创建根代码生成节点(当然还有一些静态提升的东东,这里暂时先不描述了)。

创建transform上下文

function createTransformsContext(root, options) {const context = {root,nodeTransforms: options.nodeTransforms || [],helpers: new Map(),helper(key) {context.helpers.set(key, 1)}···}return context
} 

transform上下文对象中维护了一些配置,这里我们就把核心流程中主要用的配置拿了出来。比如整个ast节点,转换过程中需要调用的一些转换函数。

遍历AST节点

function traverseNode(node: any, context) {// 节点转换函数const nodeTransforms = context.nodeTransformsconst exitFns: any = []for (let i = 0; i < nodeTransforms.length; i++) {const transform = nodeTransforms[i]// 有些转换函数会设计一个退出函数,在处理完子节点后执行const onExit = transform(node, context)if (onExit) exitFns.push(onExit)}switch (node.type) {case NodeTypes.INTERPOLATION:// 需要导入toString辅助函数context.helper(TO_DISPLAT_STRING)breakcase NodeTypes.ROOT:case NodeTypes.ELEMENT:// 遍历子节点traverseChildren(node, context)breakdefault:break}// 执行转换函数返回的退出函数let i = exitFns.lengthwhile (i--) {exitFns[i]()}
} 

traverseNode递归的遍历ast中的每个节点,然后执行一些转换函数,有些转换函数还会设计退出函数,然后用exitFns接收,这些退出函数在子节点处理完毕之后执行,因为有些逻辑需要依赖子节点处理完毕的结果。

下面我们来看下转换函数,这里我们主要讲解3种转换函数:Element、表达式和Text

Element转换函数

export const transformElement: NodeTransform = (node, context) => {
//返回退出函数 return function postTransformElement() {node = context.currentNode!if (!(node.type === NodeTypes.ELEMENT &&(node.tagType === ElementTypes.ELEMENT ||node.tagType === ElementTypes.COMPONENT))) {return}const { tag, props } = nodeconst isComponent = node.tagType &
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值