编写 Babel 插件

必要工具

yarn add babel-core babel-types

插件结构

export default function(babel) {
  return {
    visitor: {
      // visitor contents
    }
  };
}

直接取出 babel.types 会更方便:

export default function({ types: t }) {
  return {
    visitor: {
      // visitor contents
    }
  };
}

示例:基础用法

module.exports = function({ types: t }) { // 将插件导出
  return {
    visitor: {
      BinaryExpression(path) {
        if (path.node.operator !== "===") {
          return;
        }
        path.node.left = t.identifier("left");
        path.node.right = t.identifier("right");
      }
    }
  }
};

配置:

module.exports = {
  plugins: ["test"]
};

比如有以下源码:

console.log(a === b);

其 AST 形式如下:

{
  type: "BinaryExpression",
  operator: "===",
  left: {
    type: "Identifier",
    name: "foo"
  },
  right: {
    type: "Identifier",
    name: "bar"
  }
}

将会转化为:

console.log(left === right);

示例:包引入替换

当我们导入 lodash 中指定的工具函数时, 会将整个 lodash 打包进来

import { flattenDeep, chunk } from "lodash";

换成按需引入的写法, 但是这样写有些麻烦, 我们想由上面写法, 自动分解为下面写法

import flattenDeep from "lodash/flattenDeep";
import chunk from "lodash/chunk";

所以我们就编写一个 babel 插件来实现这一点

const babel = require("babel-core");
const types = require("babel-types");
// Babel将源码转换AST之后,通过遍历AST树(其实就是一个js对象),对树做一些修改,然后再将AST转成code,即成源码。
let visitor = {
  // import 语句解析时触发该函数
  ImportDeclaration(path, ref = { opts: {} }) {
    // path 语句抽象语法树 opts 插件参数
    let node = path.node;
    let { specifiers } = node; // 导入的包的说明符, 是个数组集合
    // 确认导入库是否是 .babelrc library属性指定库, 以及, 如果不是默认导入, 才进行按需导入加载
    if (
      ref.opts.library === node.source.value &&
      !types.isImportDefaultSpecifier(specifiers[0])
    ) {
      let newImports = specifiers.map((
        specifier // 遍历出导入的每个包的说明描述符
      ) =>
        types.importDeclaration(
          [types.importDefaultSpecifier(specifier.local)],
          // 生成import语句如 import chunk from 'library/chunk'
          types.stringLiteral(`${node.source.value}/${specifier.local.name}`)
        )
      );
      // 将原有语句写法替换为新写法
      path.replaceWithMultiple(newImports);
    }
  }
};
module.exports = function(babel) {
  return { visitor };
};

配置选项:

{
  "plugins": [
    [
      "extract",
      {
        "library": "lodash"
      }
    ]
  ]
}

测试: 运行 npm run build, 发现此时编译后的 bundle.js 变小了

如果只是对 lodash 做处理, 可以使用 babel-plugin-lodash

参考: Babel 插件编写

MIT Licensed | Copyright © 2018-present 滇ICP备16006294号

Design by Quanzaiyu | Power by VuePress