Babel插件和preset

前面的章节学习了babel的编译流程,也深入了原理,知道了怎么用babel的api来完成一些代码转换功能,但平时我们很少单独使用babel的api,更多的是封装成插件,插件可以上传到npm来复用。

这一节来学习下babel插件的格式以及preset。

plugin 的使用

首先回顾下plugin的使用,babel的plugin是在配置文件里面通过plugins选项配置,值为字符串或者数组。

{
    "plugins": ["pluginA", ["pluginB"], ["pluginC", {/* options */}]]
}

如果需要传参就用数组格式,第二个元素为参数。

plugin的格式

babel plugin有两种格式:

返回对象的函数

第一种是一个函数返回一个对象的格式,对象里有pre、visitor、post、inherits、manipulateOptions等属性。

export default function(api, options, dirname) {
  return {
    inherits: parentPlugin,
    manipulateOptions(options, parserOptions) {
        options.xxx = '';
    },
    pre(file) {
      this.cache = new Map();
    },
    visitor: {
      StringLiteral(path, state) {
        this.cache.set(path.node.value, 1);
      }
    },
    post(file) {
      console.log(this.cache);
    }
  };
} 

首先插件函数有三个参数api、options、dirname:

  • api里包含了babel的各种api,如types、template等,这些包就不需要在插件里单独引入了,直接取来用就行。
  • options就是外面传入的参数
  • dirname是目录名(不常用)

返回的对象有inheritsvisitorpostpremanipulateOptions等属性:

  • inherits: 指定继承某个插件,和当前插件的options合并,通过Object.assign的方式。
  • visitor: travers时调用的函数。
  • pre和post分别在遍历前后调用,可以做一些插件调用前后的逻辑,比如可以往file(表示文件的对象,在插件里面通过state.file拿到)中放一些东西,在遍历的过程中取出来。
  • manipulateOptions:用于修改options,是在插件里面修改配置的方式,比如syntaxt plugin一般都会修改parse options:
    Babel插件和preset

插件做的事情就是通过api拿到types、template等,通过state.opts拿到参数,然后通过path来修改AST。可以通过state放一些遍历过程中共享的数据,通过file放一些整个插件都能访问到的一些数据,除了这两种之外,还可以通过this来传递本对象共享的数据。

对象

插件的第二种格式就是直接写一个对象,不用函数包裹,这种方式用于不需要处理参数的情况。

export default plugin =  {
    pre(state) {
      this.cache = new Map();
    },
    visitor: {
      StringLiteral(path, state) {
        this.cache.set(path.node.value, 1);
      }
    },
    post(state) {
      console.log(this.cache);
    }
};

preset

plugin是单个转换功能的实现,当plugin比较多或者plugin的options比较多的时候,就会导致使用成本的增高。这个时候可以封装成一个preset,用户可以通过preset来批量引入plugin,并进行一些配置。preset就是对babel配置的一层封装。

比如使用plugin的时候,开发者需要知道每个plugin是干嘛的:
Babel插件和preset

而有preset之后就不再需要知道用到了什么插件,只需要选择合适的preset,然后配置一下,就会引入需要的插件,这就是preset的 意义。可以说preset是plugin的集合。我们学babel的内置功能就是学preset的配置,比如preset-env、preset-typescript等:

Babel插件和preset

preset和plugin格式一样,也可以是一个对象或者是一个函数,函数的参数也是一样的api和options,区别只是preset返回的是配置对象,包含plugin和preset:

export default function(api, options) {
  return {
      plugins: ['pluginA'],
      presets: [['presetsB', { options: 'bbb'}]]
  }
}

export default obj = {
      plugins: ['pluginA'],
      presets: [['presetsB', { options: 'bbb'}]]
}

ConfigItem

@babel/core提供了createConfigItem的api,用于创建配置项。之前都是字面量的形式创建的。当需要抽离配置出去的时候,可以使用createConfigItem。

const pluginA = createConfigItem('pluginA);
const presetB = createConfigItem('presetsB', { options: 'bbb'})

export default obj = {
      plugins: [ pluginA ],
      presets: [ presetB ]
  }
}

顺序

preset和plugin从形式上看差不多,但是应用顺序是不同的。

bable会按照如下顺序处理plugin和preset:

  1. 先应用plugin,再应用preset。
  2. plugin从前到后,preset从后往前。

这个顺序是babel规定的。

原文链接:https://juejin.cn/post/7317888347833417791 作者:人间无事人

(0)
上一篇 2023年12月30日 下午4:26
下一篇 2023年12月30日 下午4:36

相关推荐

发表回复

登录后才能评论