当前位置: 首页 > Web前端 > vue.js

【源码-webpack01-前置知识】AST抽象语法树

时间:2023-03-31 16:28:55 vue.js

导航[[深入01]执行上下文](https://juejin.im/post/684490...[[深入02]原型链](https://juejin.im/post/684490...[[深入03]继承](https://juejin.im/post/684490...[[深入04]事件循环](https://juejin.im/post/684490...[[深入05]CurryingPartialfunction函数记忆](https://juejin.im/post/684490...[[深入06]隐式转换与运算符](https://juejin.im/post/684490...[[深入07]浏览器缓存机制(http缓存机制)](https://juejin.im/post/684490...[[深入08]前端安全](https://juejin.im/post/684490...[[深入09]DebounceThrottle](https://juejin.im/post/684490...[[深入10]DebounceThrottle](https://juejin.im/post/684490...[[深入11]前端路由](https://juejin.im/post/684490...[[深入12]前端模块化](https://juejin.im/post/684490...[【深入13】观察者模式发布订阅模式双向数据绑定】(https://juejin.im/post/684490...[[深度14]画布](高ttps://juejin.im/post/684490...[[深入15]webSocket](https://juejin.im/post/684490...[[深入16]webpack](https://juejin.im/post/684490...[[深入17]http和https](https://juejin.im/post/684490...[[深入18]CSS-interview](https://juejin.im/post/684490...[[深入19]手写承诺](https://juejin.im/post/684490...[[深入20]手写功能](https://juejin.im/post/684490..[[react]Hooks](https://juejin.im/post/684490...[[部署01]Nginx](https://juejin.im/post/684490...[[部署02]DockerDeployvue项目](https://juejin.im/post/684490...[[部署03]gitlab-CI](https://juejin.im/post/684490...[[source-webpack01-front知识集]AST抽象语法树](https://juejin.im/post/684490...[[源码-webpack02-pre-knowledge]Tapable](https://juejin.im/post/684490...[[源码-webpack03]手写webpack-compiler简单编译过程](https://juejin.im/post/684490...[[源码]ReduxReact-Redux01](https://juejin.im/post/684490...[[源码]axios](https://juejin.im/post/684490...[[源码]vuex](https://juejin.im/post/684490...[[源码-vue01]数据响应和初始化渲染](https://juejin.im/post/684490...[[源码-vue02]计算响应nsive-初始化、接入、更新流程](https://juejin.im/post/684490...[[源码-vue03]watchlistener属性-初始化和更新](https://juejin.im/post/684490...[[源码-vue04]Vue.setandvm.$set](https://juejin.im/post/684490...[[源码-vue05]Vue.extend](https://juejin.im/post/684490...[[源码-vue06]Vue.nextTickandvm.$nextTick](https://juejin.im/post/684790...预知一些词abstract:abstract(abstractsyntaxtree:抽象语法树)Identifier:标识符Punctuator:标点符号declaration:declarationVariableDeclaration:变量声明declarator:declaratortraverse:遍历表达式:expression,expressionperformance:performance//whileparseExpression()尝试在考虑性能的情况下解析单个Expression。//whileparseExpression()将尝试解析单个Expression,同时考虑性能怀疑://如有疑问,请使用.parse()//如有疑问,请使用.parse()而不是.parseExpression()AST可视化工具查看AST可视化树图AST对象文档从javascript程序到机器可执行的机器码需要经过三个阶段语法检查:词法分析一、语法分析编译运行总结:词法分析->语法分析->编译运行AST抽象语法树:抽象语法树摘要:抽象AST应用场景代码(语法检测),代码(风格检测),代码(格式化),代码(高亮),代码(错误提示),代码(自动补全)eslintamdcmdwebpack通过babelAST解析过程转义js语法(1)读取js文件中的(字符流)(2)通过(词法分析)生成token------------词法分析也叫扫描scanner,分词阶段,token是一维数组(3)通过(语法分析)生成AST------------语法分析也叫解析器(4)生成(MachineCode)Execution----------------编译阶段也叫编译器词法分析词法分析是为了(字符流charstream)转换为(tokenstream)token是不可分割的最小单位,是一维数组(词法分析)也称为(扫描扫描仪)(词法分析器)在每个(关键字、标识符、运算符、标点符号、字符串、数字、布尔值values,comments,blankcharacters,spaces,linebreaks)等等都是一个tokenToken数组,每个对象包含(type)和(value)typevalue常见的(type)如下:Keyword(关键字)Identifier(标识符)Punctuator(标点符号)Numeric(数字)Boolean(布尔)Null(空值)最终代码被分割进入一个tokens列表,即一维数组源码1:constadd=(a,b)=>{returna+b}tokens:[{"type":"Keyword","value":"const"},{"type":"Identifier","value":"add"},{"type":"Punctuator","value":"="},{"type":"Punctuator","value":"("},{"type":"Identifier","value":"a"},{"type":"Punctuator","value":","},{"type":"Identifier","value":"b"},{"type":"Punctuator","value":")"},{"type":"Punctuator","value":"=>"},{"type":"Punctuator","value":“{”},{“类型”:“关键字”,“值”:“返回”},{“类型”:“标识符”,“值”:“a”},{“类型”:“标点符号”,"value":"+"},{"type":"Identifier","value":"b"},{"type":"Punctuator","value":"}"}]---源码2:consta=1;tokens:[{"type":"Keyword","value":"const"},{"type":"Identifier","value":"a"},{"type":"标点符号","值":"="},{"类型":"数字","value":"1"},{"type":"Punctuator","value":";"}]说明:(1)tokens是一个对象数组,有type和value属性(2)token是词法分析的最小单位不能再分解keywordkeywordidentfieridentifierpunctuatorpunctuationmarkNumeric:数字句法分析(语法分析)会将词法分析得到的token转化为(具有语法意义)(抽象语法树)同时结构(验证语法),如果有语法错误,throwasyntax最外层的错误属性包括:(type)(sourceType)(start)(end)等(bodyfont>)body:是一个(数组)包含多个(contentblockobjectstatement),每个contentblock包含typestartendkinddeclarations:相乘包含变量内容的block,这个block也是一个数组,因为变量声明可能会声明多个typestartendidtypestartendname(语句——在body数组中Object)有很多种类型,比如变量声明、函数定义、if语句、while循环等都是一个语句VariableDeclaration:变量声明FunctionDeclaration:函数定义IfStatement:if语句一句While语句:while循环源码:vara=1;AST{"type":"Program","start":0,"end":12,"body":[//---------------------------------------------body表示代码的具体内容{//----------------------------------------------------语句内容Block对象,一个body可能包含多个语句"type":"VariableDeclaration",//--------------------变量声明"start":0,"end":10,"declarations":[{"type":"VariableDeclarator",//------------------变量声明"start":4,"end":9,"id":{"type":"标识符",//----------------------标识符"start":4,"end":5,"name":"a"},"init":{"type":"Literal","start":8,"end":9,"value":1,"raw":"1"}}],"kind":"var"//------------------------------------变量类型}],"sourceType":"module"}说明:body:表示代码内容块的具体内容:body可能包含多个内容块,每个内容块使用一个表示内容块的对象包含:typestartendkinddeclarations:一个乘以变量内容的块,这个块也是一个数组,因为变量声明可能有多种类型,startendidtypestartendname,sourceType:表示语言的类型(2)body是一个数组,它的成员是语句内容块对象,因为body可以包含多个语句内容块。语句有很多种,比如变量声明、函数定义、if语句、while循环等都是一个语句VariableDeclaration:变量声明FunctionDeclaration:函数定义IfStatement:if语句while语句:while循环babel原理babel编译过程:parseparse->converttransform->generategenerateparseparse@babel/parser:将字符串转换成AST,babylon(现在是@babel/parser)是Babel中使用的JavaScript解析器。解析过程分为两阶段语法分析:字符流->token流词法分析:token流->AST@babel/parserconversiontransform@babel/traverse:主要用于遍历ASTBabel接收解析AST,并在这个遍历过程中通过(babel-traverse)对其进行(深度优先遍历)对节点进行(add),(update),(remove)操作traverse:表示遍历@babel/types:主要用来操作AST,比如(add)、(update)和(remove)操作除了手动替换,还可以使用@babel/types更方便快捷,相当于作用于AST库的lodash类@babel/traverse@babel/types生成generate@babel/generator:来转换抽象语法树被转换成Javascript字符串。转换后的AST通过babel-generator转成js代码。该过程在时间和深度上遍历了整个AST,然后构建转换后的代码字符串。@babel/generator@babel/parserbabelParser。parse(code,[options])-----------------------------------解析所有代码babelParser.parseExpression(code,[options])--------------------------解析单个表达式参数:-code:表示源代码字符串-options:配置对象,可选-allowImportExportEverywhere:默认的import和export声明只能出现在顶部,当这个选项为真时,它们可以出现在任何地方-...@babel/traverse因为(@babel/parser分析)和(@babel/generatorgeneration)基本不会变,所以重点是(@babel/traverseconversion)import*asbabylonfrom"babylon";importtraversefrom"babel-traverse";//源码stringconstcode=`functionsquare(n){returnn*n;}`;//解析parse:string->astconstast=babylon.parse(code);//converttransform:ast->modifiedasttraverse(ast,{enter(path){if(path.node.type==="Identifier"&&path.node.name==="n"){path.node.name="x";//--------------如果它是一个标识符并且标识符的名称是n,将n更改为x}}@babel/generatorimport{parse}from'@babel/parser';importg从“@babel/generator”生成;const代码='类示例{}';constast=解析(代码);constoutput=generate(ast,{/*选项*/},代码);babel转换代码大小写要求:将小写变量转换为大写//inputconstnumberFive=5;//输出常量NUMBERFIVE=5;实现过程install@babel/core--------------------babelcoremodule@babel/parser--------------------字符流->令牌流->AST@babel/traverse------------------AST->修改后的AST@babel/generator---------------修改AST->字符流npminstall@babel/core@babel/parser@babel/traverse@babel/generator-Scodeconstparser=require('@babel/解析器');consttraverse=require('@babel/traverse').default;constgenerator=require('@babel/generator').default;//源字符串constcode=`constnubmerFive=5`;//parseletAST=parser.parse(code)//converttraverse(AST,{enter(path){console.log(path.node.type,'path.node.type')if(path.node.type==='Identifier'){//如果节点类型是标识符,将名称转换为大写路径.node.name=path.node.name.toUpperCase()}}})//生成constoutputObj=generator(AST)constoutputStr=outputObj.code;console.log(outputStr,'outputStr')dataASTbabel-AST相关工具https://juejin.im/post/684490...AST从babel到ASThttps://juejin.im/post/684490...AST99%的人都不懂ASThttps://segmentfault.com/a/11...ASTabstractsyntaxtree-graphhttps://juejin.im/post/684490...AST详情:https://segmentfault.com/a/11...ASThttps://cheogo.github.io/lear...AST详情https://www.codercto.com/a/88...babel转换https://juejin.im/post/684490...babel转换案例https://cloud.tencent.com/dev...babel插件介绍https://zhuanlan.zhihu.com/p/...