前面的章节学习了babel的编译流程,也深入了原理,知道了怎么用babel的api来完成一些代码转换功能,但平时我们很少单独使用babel的api,更多的是封装成插件,插件可以上传到npm来复用。
这一节来学习下babel插件的格式以及preset。
plugin 的使用
首先回顾下plugin的使用,babel的plugin是在配置文件里面通过plugins选项配置,值为字符串或者数组。
js
{
"plugins": ["pluginA", ["pluginB"], ["pluginC", {/* options */}]]
}
如果需要传参就用数组格式,第二个元素为参数。
plugin的格式
babel plugin有两种格式:
返回对象的函数
第一种是一个函数返回一个对象的格式,对象里有pre、visitor、post、inherits、manipulateOptions等属性。
js
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是目录名(不常用)
返回的对象有inherits
、visitor
、post
、pre
、manipulateOptions
等属性:
- inherits: 指定继承某个插件,和当前插件的options合并,通过
Object.assign
的方式。 - visitor: travers时调用的函数。
- pre和post分别在遍历前后调用,可以做一些插件调用前后的逻辑,比如可以往file(表示文件的对象,在插件里面通过state.file拿到)中放一些东西,在遍历的过程中取出来。
- manipulateOptions:用于修改options,是在插件里面修改配置的方式,比如syntaxt plugin一般都会修改parse options:
插件做的事情就是通过api拿到types、template等,通过state.opts拿到参数,然后通过path来修改AST。可以通过state放一些遍历过程中共享的数据,通过file放一些整个插件都能访问到的一些数据,除了这两种之外,还可以通过this来传递本对象共享的数据。
对象
插件的第二种格式就是直接写一个对象,不用函数包裹,这种方式用于不需要处理参数的情况。
js
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是干嘛的:
而有preset之后就不再需要知道用到了什么插件,只需要选择合适的preset,然后配置一下,就会引入需要的插件,这就是preset的 意义。可以说preset是plugin的集合。我们学babel的内置功能就是学preset的配置,比如preset-env、preset-typescript等:
preset和plugin格式一样,也可以是一个对象或者是一个函数,函数的参数也是一样的api和options,区别只是preset返回的是配置对象,包含plugin和preset:
js
export default function(api, options) {
return {
plugins: ['pluginA'],
presets: [['presetsB', { options: 'bbb'}]]
}
}
或
js
export default obj = {
plugins: ['pluginA'],
presets: [['presetsB', { options: 'bbb'}]]
}
ConfigItem
@babel/core提供了createConfigItem的api,用于创建配置项。之前都是字面量的形式创建的。当需要抽离配置出去的时候,可以使用createConfigItem。
js
const pluginA = createConfigItem('pluginA);
const presetB = createConfigItem('presetsB', { options: 'bbb'})
export default obj = {
plugins: [ pluginA ],
presets: [ presetB ]
}
}
顺序
preset和plugin从形式上看差不多,但是应用顺序是不同的。
bable会按照如下顺序处理plugin和preset:
- 先应用plugin,再应用preset。
- plugin从前到后,preset从后往前。
这个顺序是babel规定的。