认识 Babel

一、babel 的用途
1.1 转译到目标环境支持的 js
这个是最常用的功能,用来把代码中的 esnext 的新的语法、flow、typescript 的语法转成基于目标环境支持的语法的实现。并且还可以把目标环境不支持的 api 进行 polyfill。
1.2 一些特定用途的代码转换
babel 是一个转译器,暴露了很多 api,用这些 api 可以完成代码到 AST 的解析、转换、以及目标代码的生成。开发者可以用它来来完成一些特定用途的转换,比如函数插桩(函数中自动插入一些代码,例如埋点代码)、自动国际化等。
1.3 代码的静态分析
对代码进行 parse 之后,能够进行转换,是因为通过 AST 的结构能够理解代码。理解了代码之后,除了进行转换然后生成目标代码之外,也同样可以用于分析代码的信息,进行一些检查。

  • linter 工具就是分析 AST 的结构,对代码规范进行检查。
  • api 文档自动生成工具,可以提取源码中的注释,然后生成文档。
  • api 文档自动生成工具,可以提取源码中的注释,然后生成文档。
    压缩混淆工具,这个也是分析代码结构,进行删除死代码、变量名混淆、常量折叠等各种编译优化,生成体积更小、性能更优的代码。
    比较流行的小程序转译工具 taro,就是基于 babel 的 api 来实现的。

二、babel 的编译整体流程
源码 -> parse -> transform -> generate -> 目标代码和 sourcemap
2.1 parse
parse 阶段的目的是把源码字符串转换成机器能够理解的 AST,这个过程分为词法分析、语法分析。

比如 let name = ‘lebron’; 这样一段源码,我们要先把它分成一个个不能细分的单词(token),也就是 let, name, =, ‘lebron’,这个过程是词法分析,按照单词的构成规则来拆分字符串成单词。

之后要把 token 进行递归的组装,生成 AST,这个过程是语法分析,按照不同的语法结构,来把一组单词组合成对象,比如声明语句、赋值表达式等都有对应的 AST 节点。

2.2 transform

  • transform 阶段是对 parse 生成的 AST 的处理,会进行 AST 的遍历,遍历的过程中处理到不同的 AST
    节点会调用注册的相应的 visitor 函数,visitor 函数里可以对 AST 节点进行增删改,返回新的
    AST(可以指定是否继续遍历新生成的 AST)。这样遍历完一遍 AST 之后就完成了对代码的修改。
  • transform -> visitor 模式(访问者模式)是 23
    种经典设计模式中的一种。visitor模式的思想是:当被操作的对象结构比较稳定,而操作对象的逻辑经常变化的时候,通过分离逻辑和对象结构,使得他们能独立扩展。

2.3 generate
generate 阶段会把 AST 打印成目标代码字符串,并且会生成 sourcemap。不同的 AST 对应的不同结构的字符串。比如 IfStatement 就可以打印成 if(test) {} 格式的代码。这样从 AST 根节点进行递归的字符串拼接,就可以生成目标代码的字符串。

三、常见的 AST 节点
3.1 Literal
Literal 是字面量的意思,比如 let name = 'guang’中,'guang’就是一个字符串字面量 StringLiteral,相应的还有数字字面量 NumericLiteral,布尔字面量 BooleanLiteral,字符串字面量 StringLiteral,正则表达式字面量 RegExpLiteral 等。
3.2 Identifier
Identifer 是标识符的意思,变量名、属性名、参数名等各种声明和引用的名字,都是Identifer。我们知道,JS 中的标识符只能包含字母或数字或下划线(“_”)或美元符号(“$”),且不能以数字开头。这是 Identifier 的词法特点。
3.3 Statement
statement 是语句,它是可以独立执行的单位,比如 break、continue、debugger、return 或者 if 语句、while 语句、for 语句,还有声明语句,表达式语句等。我们写的每一条可以独立执行的代码都是语句。
3.4 Expression
expression 是表达式,特点是执行完以后有返回值,这是和语句 (statement) 的区别。
3.5 ExpressionStatement
表达式作为语句执行的时候,你会发现解析出的 AST 包裹了一层 ExpressionStatement 节点,代表这个表达式是被当成语句执行的。
3.6 Declaration
声明语句是一种特殊的语句,它执行的逻辑是在作用域内声明一个变量、函数、class、import、export 等。
3.7 Program
program 是代表整个程序的节点,它有 body 属性代表程序体,存放 statement 数组,就是具体执行的语句的集合。
四、babel 配置
4.1 plugin 的使用和顺序
plugin 运行在 preset 之前
plugin 的顺序是从左至右
preset 的顺序是从右至左
4.2 开发 plugin 的函数形式

export default function(api, options, dirname) {
  return {
    inherits: parentPlugin,
    manipulateOptions(options, parserOptions) {
        options.xxx = '';
    },
    pre(file) {
      this.cache = new Map();
    },
    visitor: {
      StringLiteral(path, state) {
        this.cache.set(path.node.value, 1);
      }
    },
    post(file) {
      console.log(this.cache);
    }
  };
} 
  • inherits 指定继承某个插件,和当前插件的 options 合并,通过 Object.assign 的方式。
  • manipulateOptions 用于修改 options,是在插件里面修改配置的方式
  • visitor 指定 transform 时调用的函数。
  • pre 和 post 分别在遍历前后调用,可以做一些插件调用前后的逻辑,比如可以往 file(表示文件的对象,在插件里面通过
    state.file 拿到)中放一些东西,在遍历的过程中取出来。
    4.3 preset
@babel/preset-env
@babel/preset-react
@babel/preset-typescript

plugin 是单个转换功能的实现,当 plugin 比较多或者 plugin 的 options 比较多的时候就会导致使用成本升高。这时候可以封装成一个 preset,用户可以通过 preset 来批量引入 plugin 并进行一些配置。preset 就是对 babel 配置的一层封装。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值