调试网站
AST测试网站
babel插件手册
babel
consttemplate=require('@babel/template').default;constgenerate=require("@babel/generator").default;constast=template.ast(`// JSvar a = 'abcd'`);ast.kind='let';ast.declarations[0].init.value=1234;console.log(ast.declarations[0].init);console.log(generate(ast).code);这段代码通过AST把var a = 'abcd'转化为let b = 1234
babel-plugins
babel插件开发,plugin字段配合visitor筛选代码实现转化,转换的时候,是插件开始起作用的时候,babel给我们提供了一个visitor的规范,让我们进入到这个流程中,我们可以通过visitor来定义我们的访问逻辑
visitor支持很多类型,比如VariableDeclaration,FunctionDeclaration ,ImportDeclaration 等,具体可以从AST测试网站展开分析
const{
transform
}=require("@babel/core");module.exports=async(option,options)=>{let{
script,
allScript,
isExistScript,
scriptLang,
template,
templateLang,
templateComponentName,
style,
styleLang,
isExistStyle
}=optionconstresult=awaitnewPromise((resolve,reject)=>{constdefaultOption={plugins: [require("@babel/plugin-proposal-class-properties"),{visitor: {ArrayExpression(path){console.log(path.node)}}}],presets: [[require("@babel/preset-react"),{"pragma": "h",}]]}// comibine optionconstfinalOptions=Object.assign({},defaultOption,{
...options});transform(allScript,{
...finalOptions},(err,result)=>{if(err){reject(err)}else{// console.log(result)resolve(result)}});})returnresult}访问者模式
可以在方法名用|来匹配多种不同的type,使用相同的处理函数
visitor: {"ClassExpression|VariableDeclaration"(path){console.log(path.node.body)}}遍历
可以手动查找就不要遍历
path.node.params.forEach(function(){// ...});获取子节点的path
BinaryExpression(path){path.get('left');},Program(path){path.get('body.0');}获取父节点的path
获取对应的子节点的
path.find((path)=>path.isObjectExpression());path.find((path)=>path.isReturnStatement());//获取return的地方
babel-types
配合babel-types工具进行代码替换增加等
constt=require("babel-types");用多节点替换单节点
ReturnStatement(path){path.replaceWithMultiple([t.expressionStatement(t.stringLiteral("Is this the real life?")),t.expressionStatement(t.stringLiteral("Is this just fantasy?")),t.expressionStatement(t.stringLiteral("(Enjoy singing the rest of the song in your head)")),]);}还可以替换代码,不过经过测试,它有局限性,官方文档也不建议使用
FunctionDeclaration(path){path.replaceWithSourceString(`function add(a, b) { return a + b; }`);}技巧
利用visitor访问者模式获取函数片段,然后通过path.get(类型)一层一层定位到对应的子路径然后执行path.xxx改造代码片段,获取子属性可以先在AST测试网站先查找结果
visitor: {"ClassExpression"(path,{ opts }){// 筛选class myAbcAbc extends WeElement类if(path.node.superClass.name==='WeElement'&&path.get("body.body")){console.log('---------------')path.get("body.body").forEach((ClassMethod)=>{// 筛选render() {}函数if(ClassMethod.node.key.name==='render'){console.log(ClassMethod.type)ClassMethod.remove()}})}}}loader里面获取文件的路径:
constfilename=this.resourcePath;
踩过的坑
类里面的方法要使用 ClassMethod 匹配,不能使用 FunctionExpression 匹配。
参考网站
调试网站
AST测试网站
babel插件手册
babel
这段代码通过AST把
var a = 'abcd'转化为let b = 1234babel-plugins
babel插件开发,plugin字段配合visitor筛选代码实现转化,转换的时候,是插件开始起作用的时候,babel给我们提供了一个visitor的规范,让我们进入到这个流程中,我们可以通过visitor来定义我们的访问逻辑visitor支持很多类型,比如VariableDeclaration,FunctionDeclaration,ImportDeclaration等,具体可以从AST测试网站展开分析访问者模式
可以在方法名用|来匹配多种不同的
type,使用相同的处理函数遍历
可以手动查找就不要遍历
获取子节点的
path获取父节点的
pathfindParent获取对应的子节点的
babel-types
配合
babel-types工具进行代码替换增加等用多节点替换单节点
还可以替换代码,不过经过测试,它有局限性,官方文档也不建议使用
技巧
利用
visitor访问者模式获取函数片段,然后通过path.get(类型)一层一层定位到对应的子路径然后执行path.xxx改造代码片段,获取子属性可以先在AST测试网站先查找结果loader里面获取文件的路径:
踩过的坑
类里面的方法要使用 ClassMethod 匹配,不能使用 FunctionExpression 匹配。
参考网站