来源:https://github.com/jamiebuilds/babel-handbook/blob/master/translations/zh-Hans/plugin-handbook.md
Babel 的使用就是使用一些预设配置。预设就是一组插件,比如env, stage-3 flow react typescript预设。 Babel的核心就是插件,插件就是基于核心函数,对AST树的一些操作 Babel 核心的核心就是一组函数 【重要函数】 parser traverse generator core.parser core.transorm 【辅助函数】 code-frame helpers template types Babel 插件手册是官网编写的插件指南!涉及基本概念,API,转换操作,构建节点,最佳实践等部分
一、基本概念
AST抽象语法树
所有类型节点都有Node 接口以及其它参数,比如代码的起始位置,参数,左右节点等等:
代码语言:javascript复制interface Node {
type: string;
}
Babel处理步骤
Babel 的三个主要处理步骤分别是: 解析(parse),转换(transform),生成(generate)。.
遍历AST之访问者模式:
通过访问者模式,访问每一个节点! 深度递归遍历整个树。
1、访问者名字:
最普通是用Node 的 type 名为访问者的名字, 它是一个函数,但有几种高级用法 ,见下面示例
代码语言:javascript复制const MyVisitor = {
// 1、所有节点类型进入 参见:https://www.babeljs.cn/docs/babel-traverse#usage
enter(path){}
// 2、某类型的进入或退出
Identifier: {
enter() {
console.log("Entered!");
},
exit() {
console.log("Exited!");
}
}
// 3、通过某个类型名称
MemberExpression(){ }
// 4、通过helps中定义 的 别名
Function(path) {}
// 5、同时匹配几种类型
"ExportNamedDeclaration|Flow"(path) {}
}
babel-types中已定义一组别名,比如Function 可以代表多种Node类型, FunctionDeclaration
, FunctionExpression
, ArrowFunctionExpression
, ObjectMethod
and ClassMethod
。参见下面源码
2、访问者的参数--path:
第一感觉,这个参数应该是Node,但通过前面代码可以发现它叫:path。
其实参数是Path对象,它是表示两个节点之间连接的对象。 在巨大的AST树中,用来表示节点的位置的对象,Path对象的node才是节点本身,parent是父节点对象。 还有其它很多相关属性, 恩,想想也满合理的设计,为插件编写者省了不少力!
代码语言:javascript复制{
"parent": {...},
"node": {...},
"hub": {...},
"contexts": [],
"data": {},
"shouldSkip": false,
"shouldStop": false,
"removed": false,
"state": null,
"opts": null,
"skipKeys": null,
"parentPath": null,
"context": null,
"container": null,
"listKey": null,
"inList": false,
"parentKey": null,
"key": null,
"scope": null,
"type": null,
"typeAnnotation": null
}
3、执行访问者:
traverse(someAST , MyVisitor )
每一个path对象也可以traverse. path.traverse( SomeVisitor , contextObj) 。此时就不传入AST了,因为path已然包含AST信息, 第二个参数contextObj是表示传入SomeVisitor访问都的上下文,可以通过this.xxxValue来访问。
4、(访问者间的)States
官方的例子看的人难受, 我以为它是想说明这样一个问题:
所有的匹配到的访问者函数会被调用,在函数中,不应该使用全局变量(也访问者函数之外的变量),来维护某一个States。
如果我在某一个访问函数中,计算出一个值,想把这个值传递给下级的AST树,让下级节点处理某一个操作时, 应该在当前位置执行一个新的traverse, 此即相当于嵌套递归。 前面的计算值可以通过对象contextObj 传递给下级AST树 path.traverse( SomeVisitor , contextObj)
5、Scopes 和 Binding
说实话,真看不懂呀!