Babel初识

117 阅读6分钟

1.babel由来

babel原名6to5,即es6es5,在那个浏览器还不能完全支持es6的年代,需要将es5+的代码都转换成es5,这样才能使浏览器可以正常解析运行源码。后来随着js标准的不断发展,更是有了es7,es8到如今的es2023等等,因此也不能再叫6to5了,所以就改名叫做babel

2.babel用途

  • esnexttypescriptflow转译成目标环境支持的js代码
    这个是最常用的功能,用来将代码中的esnext代码等转换为目标环境(如浏览器)支持的语法,并且可以将目标环境不支持的新语法或者api进行polyfill

    babel7提供了@babel/preset-env的包,可以指定目标的环境进行按需转换,转换的更加精准,转换的代码更小。

  • 一些特定用途的代码转换
    babel是一个转译器,暴露了很多的api,使用这些api可以完成代码到AST解析、转换、目标代码的生成

    开发者可以利用这些api完成一些特定用途的转换,比如函数埋点自动国际化等。

  • 代码的静态分析 对代码进行parse之后,会生成AST,通过AST可以解析代码结构,除了转换AST之外还有分析代码的信息,做一些静态检查之类的工作。

    linter工具:分析AST结构,对代码规范进行检查。
    api 文档自动生成工具:可以提取代码中的注释,自动生成文档。
    type checker:会根据从AST中提取的或推导的类型信息,对AST进行类型是否一致的检查,从而减少运行时因类型不一致而导致的错误。
    压缩混淆工具: 分析代码结果,进行删除死代码,变量名混淆,常量折叠等各种编译优化,生成体积更小,性能更优的代码。
    js解释器: 除了对AST进行各种检查和信息的提取之外,还可以直接解释和执行AST

3.babel的编译流程

(1). 转译器和编译器

编译的定义就是从一种编程语言到另一种编程语言,主要是指从高级语言到低级语言。

高级语言:有很多用于描述逻辑的语言特性,比如分支、循环、函数、面向对象等,接近人的思维,可以让开发者通过它来快速的表达各种逻辑。
低级语言:可以与机器直接交互的语言,如汇编语言,机器语言等。

一般编译器Compiler是指从高级语言到低级语言的转换工具,而从高级语言到高级语言的转换工具叫做转译器(Transpiler)

(2). babel 的编译流程

babel是source to source 转换,整体编译流程分为三步:

  • parse: 通过parser将源码转换为AST(抽象语法树)。
  • transform: 遍历AST,调用各种transform插件对AST进行增删改。
  • generate: 把转换后的AST打印成目标代码,并生成sourcemap image.png

(3). 为什么babel的编译流程会分为parse、transform、generate三步

源码是一串按照语法格式来组织的字符串,这种高级语言人可以理解,但是计算机理解不了,所以想要计算机可以解析就需要将其转化为低级语言(计算机可以识别的语言),通过不同的对象来保存不同的数据,并且按照依赖关系组织起来,这种数据结构就是抽象语法树(AST, abstract syntax tree)。

为什么叫抽象语法树?:是因为数据结构中省略了一些没有具体意义的分隔符,比如; { }等(这些是为了方便人来阅读的,可阅读性)。

有了AST,计算器就可以理解源码字符串的意思,而理解源码是能够转换的前提。所以编译的第一步需要将源码转换(parse)为AST。

转化成AST之后就可以通过修改AST的方式来修改代码,这一步会遍历AST并进行各种增删改,这一步是babel最核心的部分。

经过转换之后的AST就是符合要求的代码,就可以再转换为字符串,转回字符串的过程中把之前删掉的一些分隔符再加回来。

总结来说就是:为了让计算机理解代码需要先对源码字符串进行parse,生成AST,把对代码的修改转为对AST的增删改,转换为AST之后再打印成目标代码字符串。

(4).转换的三步(parse、transform、generate)中都做了什么

  • parse
    parse阶段是把源码字符串转换为机器能够理解的AST,这个过程分为词法分析、语法分析。
    比如let name = 'xiaogang';这一段代码,首先需要将它分成一个个不能细分的单词(token),也就是let,name,=,'xiaoganng',这个过程是词法分析,按照单词的构成规则来拆分字符串成单词。
    之后要把token进行递归的组装,生成AST,这个过程是语法分析,按照不同的语法结构,来把一组单词组合成对象,比如声明语句、赋值表达式等都有对应的AST节点。 image.png
  • transform 这个阶段是对parse生成的AST进行处理,会进行AST的遍历,遍历的过程中处理到不同的AST节点会调用注册的相应的visitor函数,visitor函数里可以对AST节点进行增删改,返回新的AST(可以指定是否继续遍历新生成的AST)。这样遍历完一遍AST之后就完成了对代码的修改。
  • generate 这一步会把AST打印成目标代码字符串,并且会生成sourcemap。不同的AST对应的不同结构的字符串。比如IfStatement就可以打印成if(){}格式的代码。这样从AST根节点进行递归的字符串拼接,就可以生成目标代码的字符串。
    image.png sourcemap记录了源码到目标代码的转换关系,通过它我们可以找到目标代码中的每一个节点对应的源码的位置,用于调试的时候把编译后的代码映射回原代码,或者线上报错的时候把报错位置映射到源码。

4.总结

sourcemap是记录源码到目标代码的关系,并不是源码