babel-plugin

114 阅读2分钟

必须:

@babel/core,下面全部是@babel/core的dependency,所以安装@babel/core就可以了 使用包:

  • @babel/parser -转换code为ast tree
  • @babel/traverse -遍历ast tree
  • @babel/generate -生成新的code
  • @babel/core
    • types 必须使用,构造新的节点,判断ast节点类型;
    • transformSync 整合parser,traverse,generate的方法,直接使用可不用自己分步调用
  • @babel/helper-plugin-utils 帮助声明plugins的帮助方法,可选;

通用思路

code -> ast -> transformed ast -> transformed code

  • 代码到ast:parser
  • 对ast进行处理:traverse
  • 将ast生成code:generate

如何写一个babel插件的前提

  • 知道input是什么,input的ast是什么
  • 知道output是什么,output的ast是什么
  • 思考从input到output是什么 和写一个函数相似,知道输入输出后,在内部进行语法树操作,得到想要的ast,再将ast转成code即可;(此part一般babel都帮忙做了)

babel转化的方法

transformSync

常用的babel 构建AST Tree的方法

转换必然包含构建新的树,需要合理利用api,来看最终目的节点里面转换出来是什么类型的,选择该类型的节点构造起,节点构造太多,只有在实践中积累;

  • memberExpression(object, property): obj.name
  • callExpression(callee, arguments): func(x) 被调用者 + 参数
  • identifier(name); a,定义一个变量
  • binaryExpression(operator, left, right); a + b 这种
  • assignmentExpression(operator, left, right); 分配操作
  • variableDeclaration(kind, declaration); // 声明变量
t.assignmentExpression(
        "=",
        t.identifier('x'),
        t.identifier(10),
      );
 // x = 10

包括她自身的判断方法isXXX,具体可以在网站查看

代码层面

这里是plugin实例

普通-step-by-step

// 高级版,使用babel-core提供的功能babel.transformSync
const babel = require('@babel/core');
const code = 'const x = 10';

const result = babel.transformSync(code, {
  // 默认是false,指定是true才会生成
  ast: true,
  plugins: [
    function myTransformPlugin() {
      return {
        visitor: {
          Identifier(path) {
            console.log(path);
            if (path.isIdentifier({ name: 'x'})) {
              path.node.name = 'n';
            }
          }
        }
      }
    }
  ]
});

console.log(result, result.code);

优化-使用transformSync

const babel = require('@babel/core');
// source
const code = `
  function hello(name) {
    return 'hello' + name;
  }
  console.log(hello('shelly'));
`;
// traget:
// function olleh(eman) {
//   return 'h' + 'e' + 'l' + 'l' + 'o' + eman;
// }
// console.log(olleh('shelly'));
function myCustomeplugin() {
  return {
    // traversal 阶段,深度优先遍历搜索语法树,visit ast的每个节点
    // 可以对每种类型的节点,来visit; 比如Identifier,StringLiteral
    visitor: {
      Identifier(path) {
        console.log(path, 'path', path.node.name, path.parentPath.isMemberExpression() );
        if (!path.parentPath.isMemberExpression()) {
          path.node.name = path.node.name.split('').reverse().join('');
        }
      },
      StringLiteral(path) {
        console.log('stringliteral', path.node);
        const newNode = path.node.value
        .split('')
        .map((c) => babel.types.stringLiteral(c))
        .reduce((total, cur) => babel.types.binaryExpression('+', total, cur));
        path.replaceWith(newNode);
        // 添加了新下级,如果往下遍历,会无限循环
        path.skip();
      }
    }
  }
}

const result = babel.transformSync(code, {
  plugins: [myCustomeplugin]
});
console.log(result, result.code);

必用网站

babel-types参考手册builder+validator
ast树生成探索,看到转换后的
babel-core node api

参考:# Step-by-step guide for writing a custom babel transformation