探索 babel和babel 插件是怎么工作的

作者:侯增皓

https://www.hazyzh.com/b/180211145458

你有可能会听到过这个词webpack工程师,这个看似像是一个专业很强的职位其实很多时候是一些前端对现在前端工作方式对一些吐槽,对于一个之前没有接触过,,之类的工具的人来说,看到大量的配置文件后很多人都会看懵。

很多人就干脆不管这些东西,直接上手写业务代码,把这些构建工具就相当于,我们把所有的文件都经过这些工具最终生成一个或者几个打包后的文件,其中关于优化和代码转换问题其实一大部分都是在这些配置里面的。如果我们不去了解其中的一部分原理,后面遇到很多问题()时候都是束手无策,而且万一哪天构建工具出现问题时候可能连工作都开展不下去了。

既然我们日常都要用到,最好的方式就是去研究一下这些工具的原理的作用,让这些工具成为我们手中的利器,而不是工作上的绊脚石,而且这些工具的设计者都是顶级的工程师,当你敲开壁垒探究内部秘密时候,我相信你会感受到其中的编程之美。

这里我们去探索一下的原理。

babel 是什么?

Babel · The compiler for writing next generation JavaScript

6to5

你在上可以看到这样一个包名字是6to5(https://www.npmjs.com/package/6to5),光看名字可能会让人感觉到很诧异,名字看起来可能有点奇怪,其实在开始的时候名字就是这个。简单粗暴,一下子就看懂了是用来干啥的,但是很明显这不是一个好名字,这个名字会让人感觉到普及之后这个库就没用了,为了保持活力这个库可能要不停的修改名字。下面是作者一次分享中假设如果按这个命名法则可能出现的名称。

很明显发生这种情况是很不合理的,团队内部经过大量讨论后,最终选择了,这与电影银河系漫游指南中的Babel fish相应,也有关系到圣经中的一个故事Tower of Babel(https://en.wikipedia.org/wiki/TowerofBabel)。(ps.优秀的人总是也很有情怀。)

babel is the new jQuery

的作者曾说过这样一句话,可以换一种理解为

对于就相当于对于, 就是说给予了我们便捷查询和修改的能力。抽象语法树 后面会讲到。

为什么要用babel转换代码

我们之前做一些兼容都会都会接触一些的概念,比如如果某个版本的浏览器不支持方法,但是我们的代码中有用到的函数,为了支持这些代码,我们会人为的加一些兼容代码。

对于这种情况做兼容也很好实现,引入一个文件就可以了,但是有一些情况我们使用到了一些新语法,或者一些其他写法:

这种情况靠,因为一些浏览器根本就不识别这些代码,这时候就需要把这些代码转换成浏览器识别的代码。就是做这个事情的。

babel做了哪些事情

为了转换我们的代码,做了三件事:

解析我们的代码转换为 。

利用我们配置好的 把 生成的 转变为新的 。

把转换后的 生成新的代码

从图上看占了很大一块比重,这个转换过程就是中最复杂的部分,我们平时配置的就是在这个模块起作用。

从简单的说起

可以看到要想搞懂, 就是去了解上面三个步骤都是在干什么,我们先把比较容易看懂的地方开始了解一下。

Parser 解析

解析步骤接收代码并输出,这其中又包含两个阶段词法分析语法分析。词法分析阶段把字符串形式的代码转换为流。语法分析阶段会把一个令牌流转换成的形式,方便后续操作。

Generator 生成

代码生成步骤把最终(经过一系列转换之后)的 AST 转换成字符串形式的代码,同时还会创建源码映射(source maps)。代码生成其实很简单:深度优先遍历整个 AST,然后构建可以表示转换后代码的字符串。

babel的核心内容

看起来的主要工作都集中在把解析生成的经过然后去生成这上面了。

AST抽象语法树

我们一直在提到它究竟是什么呢,既然它的名字叫做,我们可以想象一下如果把我们的程序用树状表示会是什么样呢。

我们想象一下要表示上述代码应该是什么样子,首先必须有东西可以表示这些具体的,,的具体信息,比如,有了这些信息还不够,我们必须建立起它们之间的关系,比如。有了这些信息我们就可以还原这个程序,这也是把代码解析成时候所做的事情,对应上面我们说的和。

在中我们用(节点)来表示各个代码片段,比如我们上面程序整体就是一个节点节点(所有的 AST 根节点都是 Program 节点),因为它下面有两条语句所以它的属性上就两个声明节点。所以上面程序的就类似这样。

可以看到在节点上用各个的属性去表示各种信息以及程序之间的关系,那这些节点每一个叫什么名字,都用哪些属性名呢?我们可以在说明文档(https://github.com/babel/babylon/blob/master/ast/spec.md#variabledeclaration)上找到这些说明。

关于接口

看这个文档时候我们可以看到说明大多是类似这种

这里提到 interface这个我们在其他语言中是比较常见的,比如 Node规定了 type和 loc属性,如果其他节点继承自 Node,那么它也会实现 type和 loc属性就是说继承自 Node的节点也会有这些属性,基本所有节点都继承自 Node,所以我们基本可以看到 loc这个属性 loc表示个一些位置信息。

节点单位

我们程序很多地方都会被拆分成一个个的节点,节点里面也会套着其他的节点,我们在文档中可以看到结构的各个节点都很细微,比如我们声明函数,函数就是一个节点,函数名和形参那么参数都是一个变量节点。生成的节点往往都很复杂,我们可以借助astexplorer来帮助我们分析结构。

图像展示

有了上面这些概念我们已经可以大概了解的概念,以及各个模块代表的含义,假设我们有这样一个程序,我们用图形简易的分析下它的结构:

节点遍历

经过一番努力我们终于了解了以及其中内容的含义,但是这一部分基本不需要我们做什么,会借助Babylon帮我们生成我们需要的结构。我们更多要去做的是去修改和改变生成的这个抽象语法树。

拿到抽象语法树后会使用进行递归的树状遍历,对于每一个节点都会向下遍历到尽头,然后向上遍历退出分支去寻找下一个分支。这样确保我们能找到任何一个节点,也就是能访问到我们代码的任何一个部分。可是我们要怎么去完成修改操作呢,给我们提供了下面这两个概念。

visitor

我们已经知道会遍历节点组成的抽象语法树,每一个节点都会有自己对应的,比如变量节点等。我们需要给提供一个对象,在这个对象上面我们以这些节点的做为,已一个函数作为值,类似如下:

这样在遍历进入到对应到节点时候,就会去执行对应的函数,向上遍历退出对应节点时候,就会去执行对应的函数,接着上面的代码我们可以做一个测试。

我们执行对应代码可以看到上面和函数分别执行了四次:

从上面简单的代码上也可以看到四个变量,它们应该属于同一级别的节点树上,所以遍历时候会分别进入对应节点然后退出再去下一个节点。

Paths

我们通过可以在遍历到对应节点执行对应的函数,可是要修改对应节点的信息,我们还需要拿到对应节点的信息以及节点和所在的位置,在遍历到对应节点执行对应函数时候会给我们传入参数,辅助我们完成上面这些操作。注意是表示两个节点之间连接的对象,而不是当前节点,我们上面访问到了节点,它传入的参数看起来是这样的:

从上面我们可以看到表示两个节点之间的连接,通过这个对象我们可以访问到节点、父节点以及进行一系列跟节点操作相关的方法。我们修改一下上面的函数

在执行一下上面的代码就可以看到 name打印出来的依次是 a, b, c, d。这样我们就有可以修改操作我们需要改变的节点了。另外 path对象上还包含添加、更新、移动和删除节点有关的其他很多方法,我们可以通过文档去了解。

一些有用的工具

为了方便我们开发,在每一个环节都有很多人性化的定义也提供了很多实用性的工具,比如之前我们在定义时候分别定义了,函数,可很多时候我们其实只用到了一次在的时候做一些处理就行了。所以我们如果我们直接定义节点的为函数,就相当于定义了函数。

上面我们还提到了plugins是函数的情况,其实我们写的差距一般都是一个函数,这个入口函数上也会穿入一个,这是一个用于节点的式工具库(类似对于的帮助), 它包含了构造、验证以及变换 AST 节点的方法。 该工具库包含考虑周到的工具方法,对编写处理AST逻辑非常有用。

实际运用

假如我们有如下代码:

我们发现这里把简写成了,为了让这些代码可以执行,我们现在用装置去转换一下这些代码。

改变log函数调用本身

既然是没有写全,我们就改变这个函数调用的地方,把每一个替换成,我们看一下属于函数执行语句,相对应的节点就是,我们看下它的结构:

是我们函数执行的名称,就是我们穿入的参数,参数我们不需要改变,只需要把函数名称改变就好了,之前的是一个变量,我们现在要把它变成一个表达式,我们看一下手册可以看到是一个类型的值,这里也可以借助之前提到的网站astexplorer(https://astexplorer.net/)来帮助我们分析。有了这些信息我们就可以去实现我们的目的了,我们这里手动引入一下辅助我们创建新的节点。

执行后我们可以看到结果:

直接在模块中声明log

这里简单的修改下visitor:

执行后生成的代码为:

总结

到这里我们已经简单的分析代码,修改一些抽象语法树上的内容来达到我们的目的,但是还是有很多中情况还没考虑进去,而现阶段不仅仅代表着去转换代码之类的功能,实际上我们自己可以写出很多有意思的插件,欢迎来了解,按照自己的想法写一些插件或者去贡献一些代码,相信在这个过程中你收获的绝对比你想象中的要更多!

觉得本文对你有帮助?请分享给更多人

关注「前端大全」,提升前端技能

淘口令:复制以下红色内容,再打开手淘即可购买

范品社,使用¥极客T恤¥抢先预览(长按复制整段文案,打开手机淘宝即可进入活动内容)

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180303B1A5XE00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券