Babel 插件
作者:知否
来源:SegmentFault 思否社区
Babel 是一个编译器,和其他编译器一样,编译过程分为三个阶段,分别是解析(parsing)、转换(transforming)和生成(generate)。其中分析和生成阶段由 Babel 核心完成,而转换阶段,则由Babel插件完成。所以如果我们要实现代码的转换,需要为 Babel 添加插件。Babel 也提供了很多的接口来供我们编写自身的插件来转换我们的实际代码。
插件的介绍
下面是一个典型的 Babel 插件结构:
export default function({ types: babelTypes }) {
  return {
    visitor: {
      Identifier(path, state) {},
      ASTNodeTypeHere(path, state) {}
    }
  };
};
其中我们需要关注的内容如下:
- babelType:类似 lodash 那样的工具集,主要用来操作 AST 节点,比如创建、校验、转变等。例如判断某个节点是不是标识符。 
- path:AST 中有很多节点,每个节点可能有不同的属性,并且节点之间可能存在关联。path 是个对象,它代表了两个节点之间的关联。我们可以在 path 上访问到节点的属性,也可以通过 path 来访问到关联的节点。 
- state:代表了插件的状态,我们可以通过 state 来访问插件的配置项。 
- visitor:Babel 采取递归的方式访问 AST 的每个节点,之所以叫做 visitor,只是因为有个类似的设计模式叫做访问者模式,不用在意背后的细节。 
- Identifier、ASTNodeTypeHere:AST 的每个节点,都有对应的节点类型,比如标识符、函数声明等,可以在 visitor 上声明同名的属性,当 Babel 遍历到相应类型的节点,属性对应的方法就会被调用,传入的参数就是 path、state。 
插件的使用
npm install --save-dev @babel/cli
module.exports = function({ types: babelTypes }) {
    return {
      name: "simple-plugin-replace",
      visitor: {
        Identifier(path, state) {
          if (path.node.name === 'a') {
            path.node.name = 'xkd';
          }
        }
      }
    };
};
var a = 10;
function func(){
    var a = 20;
    console.log(a);
}
npx babel --plugins ./plugin.js index.js
"use strict";
var xkd = 10;
function func() {
    var xkd = 20;
    console.log(xkd);
}
插件配置
{
    "plugins": [ ["./plugin", {
      "a": "one",
      "b": "two"
    }] ]
}
module.exports = function({ types: babelTypes }) {
  return {
    name: "simple-plugin-replace",
    visitor: {
      Identifier(path, state) {
        let name = path.node.name;
        if (state.opts[name]) {
          path.node.name = state.opts[name];
        }
      }
    }
  };
};
let a = 10;
let b = 20;
let one = 10;
let two = 20;
转译插件
ES3
- member-expression-literals 
- property-literals 
- reserved-words 
ES5
- property-mutators 
ES2015
- arrow-functions 
- block-scoped-functions 
- block-scoping 
- classes 
- computed-properties 
- destructuring 
- duplicate-keys 
- for-of 
- function-name 
- instanceof 
- literals 
- new-target 
- object-super`
- parameters 
- shorthand-properties 
- spread 
- sticky-regex 
- template-literals 
- typeof-symbol 
- unicode-escapes 
- unicode-regex 
ES2016
- exponentiation-operator 
ES2017
- async-to-generator 
ES2018
- async-generator-functions 
- dotall-regex 
- named-capturing-groups-regex 
- object-rest-spread 
- optional-catch-binding 
- unicode-property-regex 
Modules
- modules-amd 
- modules-commonjs 
- modules-systemjs 
- modules-umd 
Experimental
- class-properties 
- decorators 
- do-expressions 
- export-default-from 
- export-namespace-from 
- function-bind 
- function-sent 
- logical-assignment-operators 
- nullish-coalescing-operator 
- numeric-separator 
- optional-chaining 
- partial-application 
- pipeline-operator 
- private-methods 
- throw-expressions 
- private-property-in-object 
语法插件
{
  "parserOpts": {
    "plugins": ["jsx", "flow"]
  }
}

