Appearance
babel 插件
其实 babel 插件就是一个包含 visitor 的对象,visitor 是对象,属性就是 AST 语法树节点的 type 名称
babel 插件的核心: 将老的语法树转成新的语法树
- @babel/core Babel 的编译器,核心 API 都在这里面,比如常见的 transform、parse
- babylon Babel 的解析器
- babel-types 用于 AST 节点的 Lodash 式工具库, 它包含了构造、验证以及变换 AST 节点的方法,对编写处理 AST 逻辑非常有用
- babel-traverse 用于对 AST 的遍历,维护了整棵树的状态,并且负责替换、移除和添加节点
- babel-types-api
- Babel 插件手册
- babeljs.io babel 可视化编译器
转换箭头函数
@babel/core
的 transform
方法 包含了:
- 将源代码转成 AST 语法树(类似
@babel/parser
、esprima.parse(sourceCode)
) - 遍历抽象语法树,并调用插件将语法树转成新的语法树(类似
@babel/traverse
、estraverse.traverse( ast , { enter(){} , leave(){} } )
) - 将新的语法树生成代码(类似
@babel/generator
、escodegen.generate(ast)
)
const core = require('@babel/core');
const types = require('babel-types');
const sourceCode = `
const sum = (a,b)=>{
console.log(a+b)
}
`;
const BabelPluginTransformEs2015ArrowFunctions = {
visitor: {
ArrowFunctionExpression(nodePath) {
const node = nodePath.node;
node.type = 'FunctionExpression';
}
}
};
let { code: es5Code, map, ast } = core.transform(sourceCode, {
plugins: [BabelPluginTransformEs2015ArrowFunctions]
});
console.log(es5Code.code);
/* 结果:
const sum = function (a, b) {
console.log(a + b);
};
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
处理 this 指向
let core = require('@babel/core');
let types = require('babel-types');
let BabelPluginTransformEs2015ArrowFunctions = require('babel-plugin-transform-es2015-arrow-functions');
const sourceCode = `
const sum = (a,b)=>{
console.log(this);
return a+b;
}
`;
//babel插件其实是一个对象,它会有一个visitor访问器
let BabelPluginTransformEs2015ArrowFunctions2 = {
//每个插件都会有自己的访问器
visitor: {
//属性就是节点的类型,babel在遍历到对应类型的节点的时候会调用此函数
ArrowFunctionExpression(nodePath) {
//参数是节点的数据
let node = nodePath.node; //获取 当前路径上的节点
//处理this指针的问题
hoistFunctionEnvironment(nodePath);
node.type = 'FunctionExpression';
}
}
};
function hoistFunctionEnvironment(fnPath) {
const thisEnvFn = fnPath.findParent(p => {
//是一个函数,不能是箭头函数 或者 是根节点也可以
return (p.isFunction() && !p.isArrowFunctionExpression()) || p.isProgram();
});
//找一找当前作用域哪些地方用到了this的路径
let thisPaths = getScopeInfoInformation(fnPath);
//声明了一个this的别名变量,默认是_this __this
let thisBinding = '_this';
if (thisPaths.length > 0) {
//在thisEnvFn的作用域内添加一个变量,变量名_this,初始化的值为this
thisEnvFn.scope.push({
id: types.identifier(thisBinding),
init: types.thisExpression()
});
thisPaths.forEach(item => {
//创建一个_this的标识符
let thisBindingRef = types.identifier(thisBinding);
//把老的路径 上的节点替换成新节点
item.replaceWith(thisBindingRef);
});
}
}
function getScopeInfoInformation(fnPath) {
let thisPaths = [];
//遍历当前path所有的子节点路径,
//告诉 babel我请帮我遍历fnPath的子节点,遇到ThisExpression节点就执行函数,并且把对应的路径传进去
fnPath.traverse({
ThisExpression(thisPath) {
thisPaths.push(thisPath);
}
});
return thisPaths;
}
let targetCode = core.transform(sourceCode, {
plugins: [BabelPluginTransformEs2015ArrowFunctions2]
});
console.log(targetCode.code);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62