先从一个接收了当前babel对象作为参数的 function 开始。
export default function(babel) {
// plugin contents
}
由于你将会经常这样使用,所以直接取出 babel.types 会更方便:(译注:这是 ES2015 语法中的对象解构,即 Destructuring)
export default function({ types: t }) {
// plugin contents
}
接着返回一个对象,其 visitor 属性是这个插件的主要访问者。
export default function({ types: t }) {
return {
visitor: {
// visitor contents
}
};
};
Visitor 中的每个函数接收2个参数:path 和 state
export default function({ types: t }) {
return {
visitor: {
Identifier(path, state) {},
ASTNodeTypeHere(path, state) {}
}
};
};
让我们快速编写一个可用的插件来展示一下它是如何工作的。下面是我们的源代码:
foo === bar;
其 AST 形式如下:
{
type: "BinaryExpression",
operator: "===",
left: {
type: "Identifier",
name: "foo"
},
right: {
type: "Identifier",
name: "bar"
}
}
我们从添加 BinaryExpression 访问者方法开始:
export default function({ types: t }) {
return {
visitor: {
BinaryExpression(path) {
// ...
}
}
};
}
然后我们更确切一些,只关注哪些使用了 === 的 BinaryExpression。
visitor: {
BinaryExpression(path) {
if (path.node.operator !== "===") {
return;
}
// ...
}
}
现在我们用新的标识符来替换 left 属性:
BinaryExpression(path) {
if (path.node.operator !== "===") {
return;
}
path.node.left = t.identifier("sebmck");
// ...
}
于是如果我们运行这个插件我们会得到:
sebmck === bar;
现在只需要替换 right 属性了。
BinaryExpression(path) {
if (path.node.operator !== "===") {
return;
}
path.node.left = t.identifier("sebmck");
path.node.right = t.identifier("dork");
}
这就是我们的最终结果了:
sebmck === dork;
现在我们来手写一个为开发环境debug的插件,功能是如果在开发环境下添加debug判断就继续执行条件,到了正式环境自动把debug条件下的逻辑去掉,不用自己手动去删除,达到解放你的双手。
在项目目录下创建index.js,代码如下:
module.exports = function ({ types: t }) {
return {
visitor: {
Identifier(path) {
const parentNodeIsIfStatement = t.isIfStatement(path.parent);
const isDebug = path.node.name === "DEBUG";
if (isDebug && parentNodeIsIfStatement) {
const stringNode = t.stringLiteral("DEBUG");
path.replaceWith(stringNode);
}
},
StringLiteral(path) {
console.log(path.node.value);
const parentNodeIsIfStatement = t.isIfStatement(path.parent);
const isDebug = path.node.value === "DEBUG";
if (isDebug && parentNodeIsIfStatement) {
if (process.env.NODE_ENV === "production") {
path.parentPath.remove();
}
}
},
},
};
};
然后在项目中创建babel.config.js,我这个是在vue项目中测试的,
代码如下:
module.exports = {
presets: ["@vue/cli-plugin-babel/preset"],
plugins: ["../index.js"],
};
App.js代码如下:
<template>
<div>
example
<button @click="handleClick">click</button>
</div>
</template>
<script>
export default {
name: "App",
setup() {
const handleClick = () => {
console.log("click");
if (DEBUG) {
console.log("for debug")
const a = 10;
const b = 20;
console.log(a + b);
}
};
return {
handleClick,
};
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
可以看到开发环境下是进入debug判断条件里面的,执行打包之后:
完工,是不是很简单😁