Babel 是什么

Babel 是一个 JavaScript 编译器

编译的定义就是从一种编程语言转成另一种编程语言。主要指的是高级语言到低级语言。一般编译器 Compiler 是指高级语言到低级语言的转换工具,对于高级语言到高级语言的转换工具,被叫做转换编译器,简称转译器 (Transpiler)。

所以Babel在工程化当中是用来语法转换,转换成低端环境的浏览器或者node环境也能够执行的代码,一开始是ES6转化到ES5,所以一开始也叫6to5,不过后来也跟进最新的标准,甚至可以转换到更低级的规范标准,也就更名到babel了

我们最常见的babel插件 就是

  • @babel/preset-env
  • @babel/preset-react

Babel的具体用途

  • 转译语法,比如es6、7、8、next,或者typescript等
  • 用作静态编译分析,比如混淆,api文档等
  • 自制语法糖转换

Babel的工作流程

babel本身是一个微内核的架构,即采用插件的形式工作,所以又叫做插件化架构,指的是软件的内核相对较小,主要功能和业务逻辑都通过插件实现。插件化架构一般有两个核心的概念:内核和插件,我们前端一直在用的浏览器也可以称为插件化架构,页面是插件,通过挂载的window提供API,这些就不细说了,而babel的内核即编译流程总共分为三个阶段:解析(parse),转换(transform),生成(generate):

  1. parse:源码进行词法分析和语法分析转成抽象语法树(AST)
  2. transform:遍历 AST,调用各种 transform 插件对 AST 进行增删改
  3. generate:把转换后的 AST 生成目标代码

在每个阶段都会调用各自的插件,插件的形式又分为preset和plugins,这也是插件机制里很常见的,运行机制是

  • Plugin 会运行在 Preset 之前。
  • Plugin 会从前到后顺序执行。
  • Preset 的顺序从后向前

Babel的AST

Babel的解析是一个叫babylon的parser库,babylon基于acorn,并且对 AST 节点和属性都做了扩展,其实eslint的parser也是基于acorn拓展的,acorn本身也是插件形式拓展的,所以很多工具的parser都用acorn进行拓展,感兴趣的同学也可以搜一下这份历史

在线可以用https://astexplorer.net/ 查看自己的代码的ast

比如以下:

  1. const author = "cnyballk"

image.png

Babel 的插件是如何工作的

Babel 在完成 AST 编译后,会调用插件对 AST 做修改,插件调用分为了四个阶段:

  1. 遍历插件集合,执行插件的 pre 方法。
  2. 遍历插件集合,合并插件的 visitor 方法 ,输出是一个包含了所有插件逻辑的 visitor 方法。
  3. 执行第二步合成的 visitor 方法。
  4. 遍历插件集合,执行插件的 post 方法。

很显然,我们能看到visitor 其实是合并的,这是babel为了性能而做出的选择,如果在写插件的时候需要对语法进行分析,需要在语法转换之前进行,否则可能会与@babel/preset-env等插件集的visitor 混合,以至于分析错误。

@babel/preset-env

上面介绍了工作流程以及插件的工作机制,但是平时不开发插件也不必关注,后面介绍一下常见的插件@babel/preset-env

@babel/preset-env是一个智能预设,可让您使用最新的JavaScript,而无需微观管理目标环境所需的语法转换(以及可选的浏览器polyfill)。这都使您的生活更轻松,JavaScript包更小!

env是一个插件集,首先插件集是什么?大家可以想一想语法这么多plugin,一个个install再进行配置也要很多时间,而且大家也记不住这么多,这样就会导致使用成本升高。这时候可以封装成一个 preset,可以通过 preset 来批量引入 plugin 并进行一些配置。preset 就是对 babel 配置的一层封装

再通过暴露配置 进行精准配置,比如targets

  1. {
  2. "targets": "> 0.25%, not dead"
  3. }

或者对象,用来描述支持的最低版本的浏览器

  1. {
  2. "targets": {
  3. "chrome": "59",
  4. }
  5. }

更详尽的options可以查看https://www.babeljs.cn/docs/babel-preset-env#options

最后

Babel 从2013年至今更新了已经到了7的版本了,核心都是为了更好的将语法转换, 并且降低用户的使用成本和插件的开发成本,我们在学习的时候也需要围绕核心来学习,我们后续也可以试着用babel开发一个插件出来更好的认识Babel

参考资料

https://babeljs.io/docs/en/
https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md