1.1. Babel 是什么?
借用 Babel 官方的一句话简短介绍:
Babel is a JavaScript compiler.
Babel 其实就是一个 JavaScript 的“编译器”。但是一个简单的编译器如何会成为影响前端项目的“大杀器”呢?究其原因,主要是前端语言特性和宿主(浏览器/Node.js 等)环境高速发展,但宿主环境对新语言特性的支持无法做到即时,而开发者又需要兼容各种宿主环境,因此语言特性的降级成为刚需。
另一方面,前端框架“自定义 DSL”的风格越来越凸显,使得前端各种“姿势”的代码被编译为 JavaScript 的需求成为标配。因此 Babel 的职责半径越来越大,它需要完成以下内容:
语法转换,一般是高级语言特性的降级;
Polyfill(垫片/补丁)特性的实现和接入;引入低版本代码环境,可按需。
源码转换,比如 JSX 等。
为了完成这些编译工作,Babel 不能大包大揽地实现一切,更不能用面条式毫无设计模式可言的方式来 Coding。因此,Babel 的设计,在工程化的角度上,需要秉承以下理念:
可插拔(Pluggable),比如 Babel 需要有一套灵活的插件机制,召集第三方开发者力量,同时还需要方便接入各种工具;
可调式(Debuggable),比如 Babel 在编译过程中,要提供一套 Source Map,来帮助使用者在编译结果和编译前源码之间建立映射关系,方便调试;
基于协定(Compact),Compact 可以简单翻译为基于协定,主要是指实现灵活的配置方式,比如你熟悉的 Babelloose 模式,Babel 提供 loose 选项,帮助开发者在“尽量还原规范”和“更小的编译产出体积”之间,找到平衡。
我们总结一下,编译是 Babel 的核心目标,因此它自身的实现基于编译原理,深入 AST(抽象语法树)来生成目标代码;同时,Babel 需要工程化协作,需要和各种工具(如 Webpack)相互配合,因此 Babel 一定是庞大复杂的。
ES6代码输入 ==》 babylon进行解析 ==》 得到AST
==》 plugin用babel-traverse对AST树进行遍历转译 ==》 得到新的AST树
==》 用babel-generator通过AST树生成ES5代码