babel是一个多用的多功能的javascript编译器。主要将js代码转化为浏览器或其他特定环境下的代码,比如转换为es5格式,其主要原理是ASTs(抽象语法树),babel在处理代码的每一步都涉及或创建语法树。
什么是AST:
AST(Abstract Syntax Tree) 抽象语法树 /ˈæbstrækt ˈsɪntæks/
谁在使用:webpack和Lint等很多的工具和库的核心都是通过Abstract Syntax Tree抽象语法树这个概念来实现对代码的检查、分析等操作的。通过了解抽象语法树这个概念,你也可以随手编写类似的工具
原理:通过JavaScript Parser把代码转化为一颗抽象语法树(AST),这颗树定义了代码的结构,通过操纵这颗树,我们可以精准的定位到声明语句、赋值语句、运算语句等等,实现对代码的分析、优化、变更等操作
用途:在计算机科学中,抽象语法树(abstract syntax tree或者缩写为AST),或者语法树(syntax tree),是源代码的抽象语法结构的树状表现形式,这里特指编程语言的源代码。
ast实例:
function square(n) {
return n * n;
}
//转化后:
{
type: "FunctionDeclaration",
id: {
type: "Identifier",
name: "square"
},
params: [{
type: "Identifier",
name: "n"
}],
body: {
type: "BlockStatement",
body: [{
type: "ReturnStatement",
argument: {
type: "BinaryExpression",
operator: "*",
left: {
type: "Identifier",
name: "n"
},
right: {
type: "Identifier",
name: "n"
}
}
}]
}
}
每一层AST都有相同的结构:
{
type: "FunctionDeclaration",
id: {...},
params: [...],
body: {...}
}
{
type: "Identifier",
name: ...
}
{
type: "BinaryExpression",
operator: ...,
left: {...},
right: {...}
}
这样的每一层结构也被叫做 节点(Node)。 一个 AST 可以由单一的节点或是成百上千个节点构成。 它们组合在一起可以描述用于静态分析的程序语法。
字符串形式的 type
字段表示节点的类型(如: "FunctionDeclaration"
,"Identifier"
,或 "BinaryExpression"
)。
Babel 还为每个节点额外生成了一些属性,用于描述该节点在原始代码中的位置。
{
type: ...,
start: 0,
end: 38,
loc: {
start: {
line: 1,
column: 0
},
end: {
line: 3,
column: 1
}
},
...
}
每一个节点都会有 start
,end
,loc
这几个属性。
————————————————————————————————————————————————————
babel处理流程:
parse => transform => generate
转换步骤接收 AST 并对其进行遍历,在此过程中对节点进行添加、更新及移除等操作。 这是 Babel 或是其他编译器中最复杂的过程 同时也是插件将要介入工作的部分.
babel访问者模式:Visitors(访问者)
访问者是一个用于 AST 遍历的跨语言的模式。
1,visitors是一个对象,
2,定义了用于在一个树状结构中获取具体节点的方法。
实例:
const MyVisitor = {
Identifier() {
console.log("Called!");
}
};
这是一个简单的访问者,把它用于遍历中时,每当在树中遇见一个 Identifier
的时候会调用 Identifier()
方法。
Paths路径:
Path 是表示两个节点之间连接的对象。
path结构:
将子节点 Identifier 表示为一个路径(Path)的话,看起来是这样的:
{
"parent": {
"type": "FunctionDeclaration",
"id": {...},
....
},
"node": {
"type": "Identifier",
"name": "square"
}
}
同时它还包含关于该路径的其他元数据:
{
"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
}
State(状态)
使用递归消除全局状态,把一个访问者放进另外一个访问者里面。
const updateParamNameVisitor = {
Identifier(path) {
if (path.node.name === this.paramName) {
path.node.name = "x";
}
}
};
const MyVisitor = {
FunctionDeclaration(path) {
const param = path.node.params[0];
const paramName = param.name;
param.name = "x";
path.traverse(updateParamNameVisitor, { paramName });
}
};
path.traverse(MyVisitor);
Scopes(作用域)
JavaScript 支持词法作用域,在树状嵌套结构中代码块创建出新的作用域
在 JavaScript 中,每当你创建了一个引用,不管是通过变量(variable)、函数(function)、类型(class)、参数(params)、模块导入(import)还是标签(label)等,它都属于当前作用域。
作用域可以被表示为如下形式:
{
path: path,
block: path.node,
parentBlock: path.parent,
parent: parentScope,
bindings: [...]
}
绑定:所有引用属于特定的作用域,引用和作用域的这种关系被称作:绑定(binding)。.
常用api介绍(具体参见https://github.com/jamiebuilds/babel-handbook/blob/master/translations/zh-Hans/plugin-handbook.md)
Babylon 是 Babel 的解析器。最初是 从Acorn项目fork出来的。Acorn非常快,易于使用,并且针对非标准特性(以及那些未来的标准特性) 设计了一个基于插件的架构。
Babel Traverse(遍历)模块维护了整棵树的状态,并且负责替换、移除和添加节点。
Babel Types模块是一个用于 AST 节点的 Lodash 式工具库(译注:Lodash 是一个 JavaScript 函数工具库,提供了基于函数式编程风格的众多工具函数), 它包含了构造、验证以及变换 AST 节点的方法。
Definitions(定义)
Builders(构建器)
Validators(验证器)
Converters(变换器)babel-generator
babel-template
________________________________________________________
插件编写:
export default function({ types: t }) {
return {
visitor: {
Identifier(path, state) {},
ASTNodeTypeHere(path, state) {}
}
};
};
1,Visitor 中的每个函数接收2个参数:path
和 state
2,由于经常使用到babel.types,所以直接取出 babel.types
会更方便
编写一个基于 foo === bar; 的插件
export default function({ types: t }) {
return {
visitor: {
BinaryExpression(path) {
if (path.node.operator !== "===") {
return;
}
path.node.left = t.identifier("sebmck");
path.node.right = t.identifier("dork");
}
}
};
}
更多参见:https://github.com/jamiebuilds/babel-handbook/blob/master/translations/zh-Hans/plugin-handbook.md
参考:https://www.jianshu.com/p/b9f14f384954
https://github.com/jamiebuilds/babel-handbook/blob/master/translations/zh-Hans/plugin-handbook.md