• 肝了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
  • 相关阅读:
    Android网络请求(终) 网络请求框架Retrofit
    高手必备 | Revit插件到底哪个好?区别是什么?
    红队专题-从零开始VC++C/S远程控制软件RAT-MFC-屏幕监控
    flex布局相关总结&&实现元素框居中效果
    win搜索文件搜不到含有括号的的图片,例如(2).png 搜索不到括号,解决,System.FileName:~=“(”
    ArrayList
    matplotlib绘制柱状图(普通、堆叠、左右分布)
    《洛谷深入浅出基础篇》 图的基本应用
    谷粒商城-基础篇Day04-品牌管理
    剑指 Offer II 008. 和大于等于 target 的最短子数组
  • 原文地址:https://blog.csdn.net/web220507/article/details/127687332