编写你的第一个 Babel 插件

现在你已经熟悉了 Babel 的所有基础知识了,让我们把这些知识和插件的 API融合在一起来编写第一个 Babel 插件吧。

先从一个接收了当前babel对象作为参数的 function 开始。

  1. export default function(babel) {
  2. // plugin contents
  3. }

由于你将会经常这样使用,所以直接取出 babel.types 会更方便:(译注:这是 ES2015 语法中的对象解构,即 Destructuring)

  1. export default function({ types: t }) {
  2. // plugin contents
  3. }

接着返回一个对象,其 visitor 属性是这个插件的主要访问者。

  1. export default function({ types: t }) {
  2. return {
  3. visitor: {
  4. // visitor contents
  5. }
  6. };
  7. };

Visitor 中的每个函数接收2个参数:pathstate

  1. export default function({ types: t }) {
  2. return {
  3. visitor: {
  4. Identifier(path, state) {},
  5. ASTNodeTypeHere(path, state) {}
  6. }
  7. };
  8. };

让我们快速编写一个可用的插件来展示一下它是如何工作的。下面是我们的源代码:

  1. foo === bar;

其 AST 形式如下:

  1. {
  2. type: "BinaryExpression",
  3. operator: "===",
  4. left: {
  5. type: "Identifier",
  6. name: "foo"
  7. },
  8. right: {
  9. type: "Identifier",
  10. name: "bar"
  11. }
  12. }

我们从添加 BinaryExpression 访问者方法开始:

  1. export default function({ types: t }) {
  2. return {
  3. visitor: {
  4. BinaryExpression(path) {
  5. // ...
  6. }
  7. }
  8. };
  9. }

然后我们更确切一些,只关注哪些使用了 ===BinaryExpression

  1. visitor: {
  2. BinaryExpression(path) {
  3. if (path.node.operator !== "===") {
  4. return;
  5. }
  6. // ...
  7. }
  8. }

现在我们用新的标识符来替换 left 属性:

  1. BinaryExpression(path) {
  2. if (path.node.operator !== "===") {
  3. return;
  4. }
  5. path.node.left = t.identifier("sebmck");
  6. // ...
  7. }

于是如果我们运行这个插件我们会得到:

  1. sebmck === bar;

现在只需要替换 right 属性了。

  1. BinaryExpression(path) {
  2. if (path.node.operator !== "===") {
  3. return;
  4. }
  5. path.node.left = t.identifier("sebmck");
  6. path.node.right = t.identifier("dork");
  7. }

这就是我们的最终结果了:

  1. sebmck === dork;

完美!我们的第一个 Babel 插件。