在掘金上看见了面试官: 你了解过Babel吗?写过Babel插件吗? 答: 没有。卒,正巧自己对Babel工作原理和Babel插件开发也不够了解,赶紧来补一波吧。
基础概念
首先我们这里需要了解一些基本的概念,这篇文章介绍的很详细,我这边只提一下。
Babel
Babel 是 JavaScript 编译器,更确切地说是源码到源码的编译器,通常也叫做“转换编译器(transpiler)”。
意思是说你为 Babel 提供一些 JavaScript 代码,Babel 更改这些代码,然后返回给你新生成的代码。
AST
抽象语法树(abstract syntax tree或者缩写为AST),或者语法树(syntax tree),是源代码的抽象语法结构的树状表现形式,这里特指编程语言的源代码。
和抽象语法树相对的是具体语法树(concrete syntaxtree),通常称作分析树(parse tree)。
一般的,在源代码的翻译和编译过程中,语法分析器创建出分析树。一旦AST被创建出来,在后续的处理过程中,比如语义分析阶段,会添加一些信息。
静态分析
静态分析是在不需要执行代码的前提下对代码进行分析的处理过程 (执行代码的同时进行代码分析即是动态分析)。
静态分析的目的是多种多样的, 它可用于语法检查,编译,代码高亮,代码转换,优化,压缩等等场景。
Babel 的三个主要处理步骤分别是: 解析(parse),转换(transform),生成(generate)
解析
接收代码并输出AST。这个步骤又分为两个阶段:词法分析(Lexical Analysis)和 语法分析(Syntactic Analysis)。
词法分析
词法分析阶段把字符串形式的代码转换成令牌(tokens)流。
你可以把令牌看作是一个扁平化的语法片段数组。
如:n*n代码经过词法分析转换成令牌
每一个type有一组属性来描述该令牌:
语法分析
语法分析阶段会把一个令牌(tokens)流转换成 AST 的形式。 这个阶段会使用令牌中的信息把它们转换成一个 AST 的表述结构,这样更易于后续的操作。
这个过程我们可以通过astexplorer来查看我们代码生成的AST。
这个时候我们的AST就产生了,如下图。
PS:上图左边为我们的源代码,右边为对应生成的抽象语法树AST。
转换
转换步骤接收 AST 并对其进行遍历,在此过程中对节点进行添加、更新及移除等操作。 这是 Babel 或是其他编译器中最复杂的过程 同时也是插件将要介入工作的部分。
生成
代码生成步骤把最终(经过一系列转换之后)的 AST 转换成字符串形式的代码,同时还会创建源码映射(source maps)。
代码生成其实很简单:深度优先遍历整个 AST,然后构建可以表示转换后代码的字符串。
Babel工作原理见下图表示。
图片来源,探索 babel 和 babel 插件是怎么工作的
开发一个Babel插件
Visitors(访问者)
当我们谈及“进入”一个节点,实际上是说我们在访问它们, 之所以使用这样的术语是因为有一个访问者模式(visitor)的概念。
访问者是一个用于 AST 遍历的跨语言的模式。 简单的说它们就是一个对象,定义了用于在一个树状结构中获取具体节点的方法。
|
|
PS: 许多时候我们只需要关心进入节点,就可以使用简写 Identifier() { … } 或者 Identifier: { enter() { … } } 。
这是一个简单的访问者,把它用于遍历中时,每当在树中遇见一个 Identifier 的时候会调用 Identifier里面的enter方法和exit方法。
Paths(路径)
我们通过 visitor可以在遍历到对应节点执行对应的函数,当需要修改对应节点的信息,我们还需要拿到对应节点的信息以及节点和所在的位置 (即和其他节点间的关系), visitor在遍历到对应节点执行对应函数时候会给我们传入 path参数,辅助我们完成上面这些操作。注意 Path 是表示两个节点之间连接的对象,而不是当前节点,我们上面访问到了 Identifier节点,它传入的 path参数看起来是这样的:
|
|
这里就可以通过:path.node.name 获得当前节点的name;path.parent.id 获得父节点的id
另外path对象上还包含添加、更新、移动和删除节点有关的其他很多方法,我们可以通过文档去了解。
开始动手写插件了
输入的源代码为:yuzhenfan === wangkemei
生成的AST
省略部分属性,可以通过http://astexplorer.net查看全部属性。
输出的代码为(经过我们的插件处理):fanerge1===fanerge2
下图为node打印出Balbel输出的代码:
项目地址,非常简单的Babel插件,后续再继续学习
参考文档
Babel 插件手册
ESTree
AST Explorer
探索 babel 和 babel 插件是怎么工作的
掘金-babel插件