• 肝了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!]}
    } 
    
    • 1
    • 2

    首先是创建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
    } 
    
    • 1
    • 2

    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]()}
    } 
    
    • 1
    • 2

    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 &
    • 1
  • 相关阅读:
    贪心算法证明问题
    苹果废纸篓清空了要复原怎么办?
    Go连接Redis:快速入门
    Javascript知识【jQuery:查找元素操作&案例:模拟用户分组】
    数据仓库任务调度器-Azkaban | 案例测试<自动邮件报警通知机制>
    【python进阶】装饰器
    Oracle进程
    C语言:练习题三
    同源策略、跨域与JSONP
    计算机网络性能指标——时延,时延带宽积,RTT和利用率
  • 原文地址:https://blog.csdn.net/web220507/article/details/127687332