每种编程语言都有自己的AST。懂AST,会做一些开发,会为我们的项目开发提供很大的便利。让我们带你去了解一下:
从这篇文章中我们能学到什么?

JS AST结构和属性
Babel插件开发
JS AST简介
AST是抽象语法树。简单来说,程序是以树的形式呈现的。
每种语言都有自己的AST,并且有许多AST解析器。
回到JS本身,常见的AST解析器有:
橡子
@babel/parser
以打字打的文件
丑陋-js
等等
不同解析器分析出来的AST略有不同,但本质上是一样的。
本文将以@babel/parser为例进行讲解。
让我们来看一个常见的代码
从“axios”导入ajax
转换后的AST结构如下:
{ "type": "importDeclaration "," start": 0," end": 24," loc ":{ " line ":1," column": 0 }," end": { "line": 1," column": 24 } },"说明符":[{ " type ":" importDefaultSpecifier "," start": 7," end": 11," loc": { "start": { "line": 1," column": 7}," end": { "line": 1 "," column": 11} }," local ":{ " type:" " Identifier "," " end": 24," loc": { "start": {"line": 1," column": 17 }," end": {"line": 1," column": 24 } }," extra": { "rawValue": "axios "," raw ":" axios " }," value": "axios" } }
是否有超出预期的内容?别慌,我们一点一点看。
来个简图:
进口申报
声明的类型表明它是进口申报。
常见的有:
-variable declaration:var x = ' init '
- FunctionDeclaration:函数func{}
- ExportNamedDeclaration:导出函数exp{}
- IfStatement:if{}
- WhileStatement:while{}
- ForStatement:用于{}
-不,把它们都列出来。
既然是介绍表达式,自然分为两部分:左边的是说明符,右边的是source。
说明符
ers节点将有一个保存说明符的列表。
如果左边只声明了一个变量,将给出一个importDefaultSpecifier。
如果左边有多个声明,它将是一个importSpecifier列表。
左边有多个语句是什么意思?看下面这个例子。

从“x”导入{a,b,c}
变量声明应该是唯一的。
这就是标识符的作用。
来源
Source包含一个字符串节点StringLiteral,它对应于被引用资源的位置。例子就是axios。
AST是如何转换的?
以巴别塔为例:
const parser = require let codeString = ` import Ajax from ' axios ' `;let file = parser . parse console . dir
在node中执行,就可以打印出AST了。
通过这个小例子,大家应该对AST有了初步的了解。先说说理解它的意义。
应用场景和实战
事实上,AST技术在我们的项目中随处可见。
巴别尔对es6语法的转换
Webpack的依赖关系集合
通过Uglify-js压缩代码
组件的按需加载
等等
为了更好地理解AST,我们先定义一个场景,然后进行练习。
场景:将import转换为require,类似于babel的转换。
目标:通过AST转换,语句
从“axios”导入ajax
转移
var ajax = require
为了达到这个效果,首先我们要写一个巴别塔插件。第一代码
BabelPlugin.js代码如下:
const t = require模块;exports = function Babel plugin { function需要翻译器{ var node = path节点var规格= node.specifications//Get变量名var varname =规格[0];local.name//获取资源地址var source = t . string literal var local = t . identifiervarcallee = t . identifiervarexpression = t . call expression var declarator = t . variable . Declarer//创建新节点var new node = t . variable declaration//Replace path . Replace with } return { visitor:{ import declaration { require translator . call } } };};
测试代码:
const babel = requireconst babel plugin = require let codeString = ` import Ajax from ' axios ' `;const plugins =[babel plugin]const { code } = babel . transform;控制台.目录
输出结果:
var ajax = require'
目标达成!
巴别塔插件
巴贝尔官网有开发文档。以下是对关键点的简要描述:
该插件要求返回一个访问者对象。

可以拦截所有节点。函数名是节点类型,即path。可以通过path.node获取当前节点。
@babel/types提供了大量节点操作的API,官网也有详细说明。
改变
这里的代码大家看着眼熟吗?没错,就是中的配置。babelrc。我们开发的插件可以在的插件中配置。babelrc并全球运行。
作者:cd2001cjm


