You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
function square(n) {
- return n * n;+ return n ** 2;
}
用多节点替换单节点:path.replaceWithMultiple([])
ReturnStatement(path){path.replaceWithMultiple([t.expressionStatement(t.stringLiteral("Is this the real life?")),t.expressionStatement(t.stringLiteral("Is this just fantasy?")),t.expressionStatement(t.stringLiteral("(Enjoy singing the rest of the song in your head)")),]);}
function square(n) {
- return n * n;+ "Is this the real life?";+ "Is this just fantasy?";+ "(Enjoy singing the rest of the song in your head)";
}
[多端开发系列] babel 插件开发原理理解
本文算是一个整理,借鉴了很多社区的文章,也加上了一些自己的理解。
由于 babel 开发相关资料分散在各个文章里,这里做一个整理。
这是业余项目 多端开发原理理解 的其中一篇文章。
了解 AST
参考资料:AST 抽象语法树
抽象语法树类似 DOM 树,通常有以下字段:
type: String
: 类型start: Number
: 开始位置end: Number
: 结束位置loc: Object
: 位置的具体信息编译器的工作原理
参考资料:懂编译真的可以为所欲为|不同前端框架下的代码转换
看下图:
具体到 babel 的编译,就是以下过程:
写法 1
代码字符串解析为 AST
@babel/parser
parse(code, options = {})
有第二个参数options
,默认值如下:其中,
sourceType
的值为:script
: (默认): 声明体(Statement)module
: 模块声明体(ModuleDeclaration)除了常规的语法,Babel 可以转译的语法是有限的,扩展方式通过
options.plugins
配置:estree
jsx
flow
doExpressions
objectRestSpread
decorators
classProperties
exportExtensions
asyncGenerators
functionBind
functionSent
dynamicImport
遍历并处理 AST 节点
@babel/traverse
+@babel/types
遍历 AST 的工具:
处理 AST 的工具:
从 AST 还原为代码字符串
@babel/generator
写法 2
专题:熟悉所有 AST 节点
请准备一个
test.js
,初始化内容如下,并安装依赖:打开文档:https://github.com/babel/babylon/blob/master/ast/spec.md
该文档介绍了所有的 AST 节点。
上面代码中的
traverse
的第二个参数 key 值即为文档中的节点,如:输出为:
请按照上面的写法,结合文档中的具体节点类型,写 demo 查看运行结果。重点观察
path.node
。经测算,
@vdian/traverse
遍历 ast 时但并不完全支持 babylon 的文档涉及的所有 ast 节点,应该是支持了 95% 以上的节点,这点请注意。专题:熟悉
@babel/types
即t
的 API参考文档:
根据官方文档,
t
有以下作用:构造(Builders)、验证(Validators)等。构造(Builders):
t.X()
构建器的方法名称就是您想要的节点类型的名称,除了第一个字母小写。
例如,如果您想建立一个
MemberExpression
您可以使用t.memberExpression(...)
。这些构建器的参数由节点定义决定。
节点定义如下所示:
在这里你可以看到关于这个特定节点类型的所有信息,包括如何构建它,遍历它,并验证它。
通过查看
builder
属性, 可以看到调用生成器方法所需的3个参数,每个参数可用的值可以从fileds
属性中找到。如:
创建了一个二元表达式,转为 code 如下:
验证(Validators):
t.isX
+t.assertX
如:
下面是各种举例:
检查节点类型
如果你想检查节点的类型,最好的方式是:
你同样可以对节点的属性们做浅层检查:
功能上等价于:
专题:熟悉
path
的 APIpath
顾名思义是“路径”,代码中指的是:访问
获取节点:
path.node
访问节点属性内部的
path
:path.get
检查路径类型(和
t
相同)一个路径具有相同的方法检查节点的类型:
就相当于:
检查标识符(Identifier)是否被引用
或者:
找到特定的父路径
有时你需要从一个路径向上遍历语法树,直到满足相应的条件。
对于每一个父路径调用
callback
并将其NodePath
当作参数,当callback
返回真值时,则将其NodePath
返回。.如果也需要遍历当前节点:
查找最接近的父函数或程序:
向上遍历语法树,直到找到在列表中的父节点路径
停止遍历
如果你的插件需要在某种情况下不运行,最简单的做法是尽早写回。
如果您在顶级路径中进行子遍历,则可以使用 2 个提供的 API 方法:
path.skip()
path.stop()
处理
用一个节点替换单节点:
path.replaceWith(node)
用多节点替换单节点:
path.replaceWithMultiple([])
用字符串源码替换节点
插入到容器(container)中
删除一个节点:
path.remove()
替换父节点:
path.parentPath.replaceWith
Scope(作用域)
检查本地变量是否被绑定
这将遍历范围树并检查特定的绑定。
您也可以检查一个作用域是否有自己的绑定:
创建一个 UID
这将生成一个标识符,不会与任何本地定义的变量相冲突。
提升变量声明至父级作用域
有时你可能想要推送一个
VariableDeclaration
,这样你就可以分配给它。重命名绑定及其引用
或者,您可以将绑定重命名为生成的唯一标识符:
专题:熟悉
state
state
负责接收 plugin 中的传参。插件配置举例:
babel 插件解析如下:
参考资料
The text was updated successfully, but these errors were encountered: