core 包的功能是串联整个编译流程,并且实现插件和 preset。
这节我们来实现一下 core 包。
# 思路分析
前面,我们实现了 parser、traverse、generator 包,使用方式是这样的:
分别调用 parse、traverse、generate,来完成源码的 parse、AST 的遍历和修改,以及目标代码和 sourcemap 的打印。
const sourceCode = `
const c = 1;
const d = 2;
const e = 4;
function add(a, b) {
const tmp = 1;
return a + b;
}
add(c, d);
`;
const ast = parser.parse(sourceCode, {
plugins: ['literal', 'guangKeyword']
});
traverse(ast, {
Program(path) {
Object.entries(path.scope.bindings).forEach(([id, binding]) => {
if (!binding.referenced) {
binding.path.remove();
}
});
}
});
const { code, map} = generate(ast, sourceCode, 'foo.js');
console.log(code);
console.log(map);
@前端进阶之旅: 代码已经复制到剪贴板
而如果用了 core 包,使用方式是这样的:
function plugin1(api, options) {
return {
visitor: {
Program(path) {
Object.entries(path.scope.bindings).forEach(([id, binding]) => {
if (!binding.referenced) {
binding.path.remove();
}
});
}
}
}
const { code, map } = transformSync(sourceCode, {
parserOpts: {
plugins: ['literal']
},
fileName: 'foo.js',
plugins: [
[plugin1, {}]
],
presets: []
});
@前端进阶之旅: 代码已经复制到剪贴板
可以看到,transformSync 封装了 parse、traverse、generate 的逻辑,并且还实现了插件和 preset 机制。
集成 parse、traverse、generate 比较简单,但插件和 preset 是怎么实现的呢?
插件是一个函数返回包含 visitor 的对象,我们只要把各种通过 options 传入的插件,在 transformSync 里面合并,之后把合并后的 visitors 传入 traverse 方法就可以了。
而 preset 是插件的集合,调用函数返回插件数组,之后再调用插件返回 visitor 等,然后 visitor,调用 traverse。
此外要注意的是 babel 插件的顺序是先 plugin 后 preset,plugin 从前往后、preset 从后往前。<
