在上一章节中,我们介绍了几种前端 polyfill 的方案,其中一种就提到了 Babel。相信在读的各位,都使用过 Babel(没用过的赶紧去回炉重造(゚Д゚) 。
我们在新创建一个项目的时候,都知道需要用 Babel 对代码进行转义。我们在刚使用的 Babel 的时候,往往都是打开谷歌浏览器,输入:“Babel 安装教程”。会搜索到要安装一大堆 npm 包,配置 transform-runtime、babel-polyfill… 按照第一篇文章配置之后,发现不生效,又换一篇文章,接着更改配置。终于,在快则 2 个小时,慢则一天的尝试之后,终于能够成功转译了!此时,虽然你也不知道是改动的哪一行代码生效了,也不知道为什么要这么配置,但是知道要赶紧按下保存按钮,生怕修改了配置又出问题了!祈祷下次可以直接将本次的配置拿来使用!!至于为什么要这样配置?下次一定… 下次一定…
无疑,Babel 是前端基建中重要的一环。提起 Babel,你可能会想起来一大串的名词:babel-core、babel-cli、babel-runtime,那么他们分别都有什么作用?babel 是怎么设计的?最重要的,怎么设置 babel 的配置文件?本篇文章就带大家一起了解这个让人又爱又恨的 babel。
# Babel 是什么
首先我们先来了解下 Babel 是什么,“Babel” 英文单词的含义是巴比伦文明里面的通天塔的意思。
当时地上的人们都说同一种语言,当人们离开东方之后,他们来到了示拿之地。在那里,人们想方设法烧砖好让他们能够造出一座城和一座高耸入云的塔来传播自己的名声,以免他们分散到世界各地。上帝来到人间后看到了这座城和这座塔,说一群只说一种语言的人以后便没有他们做不成的事了;于是上帝将他们的语言打乱,这样他们就不能听懂对方说什么了,还把他们分散到了世界各地,这座城市也停止了修建。这座城市就被称为“巴别城”。–《创世记》
Babel 的前身是 6to5 这个库,从字面意思就可以看出,它的主要功能是将 ES6 转成 ES5。最初的时候,转换 AST 的引擎是 frok acorn 的。在 2015 年的时候,将 6to5 这个库改名为 Babel,解析引擎改名为 Babylon。再后来,Babylon 移入到了 @babel/parser。Babylon 读出来是巴比伦的意思,指的是巴比伦文明。
我们再来看下 Babel 的官网是如何介绍 Babel 的:“Babel is a JavaScript compiler”,翻译过来为: Babel 是一个 JavaScript 的编译器。
随着前端语言特性和宿主环境的高速发展以及前端框架“自定义 DSL” 的崛起。前端各式各样的开发代码就要编译为宿主环境能够运行的 JavaScript 代码。Babel 的主要功能有:
- 语法转换:高级语言特性的降级
- polyfill:上一篇文章我们介绍过的打补丁
- 源码转换:我们可以将 jsx、vue 代码转换为浏览器可识别的 JS 代码。
Babel 的实现基于主要编译原理,深入 AST 来生成目标代码,同时,babel 也需要工程化的协作,比如要和 webpack 相互配合。
在 babel 的 monorepo 仓库 中,一共有 140+ 个包:,真是个庞大的家族呀 (⊙ˍ⊙)。我整理了个 xmind 将其比较重要的包名列举了出来。大家可以先简单看下(先混个脸熟),在下面的内容中详细给大家介绍。

# Babel 设计思想
我们平时在使用 Babel 的时候,我们想要处理哪些功能就按照某个插件,Babel 的架构模式就是这种“插件架构模式” 。插件架构模式的特点就是将扩展功能从核心模块中抽出为插件。既降低了框架的复杂度也提升了架构的灵活程度。核心模块也就是 core 和 插件 plugin 以某种轻松的方式耦合,两者在功能不变的情况下,可以独立发布,互补影响。并且可以公开插件的接口,让开发者也有机会对功能进行扩展。plugin 依赖 core 并且各 plugin 之间互相独立也可以互相通信。
# 
@babel/core 从名字就可以看出来这是 Babel 的核心库,库如其名,@babel/core 是 Babel 实现转换的核心,核心的 API 都在这个库中,比如 transform、parse、generator等。该库可以根据配置,对源码进行转换。
const babel = require("@babel/core");
babel.transform(code, options, (err, result) => {
result; // => { code, map, ast }
})
# Babel 转译过程
Babel 的转译过程主要可以分为三个步骤,解析(parse)、转换(transform)、生成(generate),那么我们分别来看下这三个步骤都做了什么.

# 解析(parse)
首先,Babel 做的第一步就是将源代码解析为 AST(Abstract Syntax Tree)也就是我们常说的抽象语法树。在《你不知道的 JavaScript(上卷)》中,第一章作用域是什么中就介绍了解析和 AST。
在生成 AST 的过程前,会先经过分词(Tokenizing)阶段,分词会将由字符组成的字符串分解成有意义的代码块,这些代码块被称为词法单元(Token)。然后将分好的词法单元组转换成一个由元素逐级嵌套所组成的代表了程序语法结构的树。这个树被称为“抽象语法树”也就是 AST。
# @babel/parser
在解析过程用到的工具包就是 @babel/parse。@babel/parse 是 JS 语言解析的解析器,其作用是接收源码,然后进行词法分析、语法分析,最终生成AST。其使用姿势如下:
