Skip to content
On this page

babel 插件

其实 babel 插件就是一个包含 visitor 的对象,visitor 是对象,属性就是 AST 语法树节点的 type 名称
babel 插件的核心: 将老的语法树转成新的语法树

转换箭头函数

@babel/coretransform 方法 包含了:

  • 将源代码转成 AST 语法树(类似@babel/parseresprima.parse(sourceCode)
  • 遍历抽象语法树,并调用插件将语法树转成新的语法树(类似 @babel/traverseestraverse.traverse( ast , { enter(){} , leave(){} } )
  • 将新的语法树生成代码(类似@babel/generatorescodegen.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

处理 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

MIT Licensed