今天是我暗恋她的第90天,但是因为组织架构的变动,我要分手了,我想换个离她暗恋对象远一点的地方在她90的日子里,997每天都在和自己的同类自相残杀,和一群老男人一起加班累死了。她是这个黑暗时代唯一的光。她是年会的主持人。我的女神,而我只是一条加班狗。她被鲜花和掌声包围。我周围都是大人物和LSP。她每天都穿着漂亮的衣服和名牌包。我只有一件黄色的上衣和一台大电脑。我配不上她,却深深被她吸引。结婚7年,我每天下班回家。我不抽烟也不喝酒。很具体,遇到她之后,我才知道,一个男人真的可以同时爱上好几个女人。临走前,我不知道该不该跟她表白。如果我表白,她肯定会说我是个好人。如果我看起来更好,对吗?没必要自卑。不幸的是,如果没有如果,我就是一个完美的垃圾。我很不高兴,所以我推出了一个版本的代码。配置文件也修改错了,线上爆发了一个大bug。所有网页都是404未找到。1000封报警邮件被炮轰老板委婉的发了1星业绩的暗示哭了配置文件,手动修改,太容易受情绪影响而出错。这些重复且容易出错的操作应该通过工程化和自动化来解决。babel修改js配置文件实现完整代码参考:github。像那些js配置文件,里面可能有很多非配置代码,可能一次要修改好几个文件。比如我们在前端项目中,要插入一个页面,需要修改router、menus等配置文件,手动复制页面模板等,对于这些高度重复的机械化操作,手动修改是非常错误的-易于。我们可以直接使用babel来操作AST抽象语法树,通过工程化进行精确修改。让babel帮我们找到指定位置,正确插入配置代码。我们在做工程开发的时候,经常会使用babel来操作AST。首先我们来了解一下ASTAST是什么,抽象语法树(AbstractSyntaxTree),它是对源代码语法结构的一种抽象表示。它以树的形式表示编程语言的语法结构。我们使用babel对AST进行转换和操作,主要分为三个步骤:parser、traverse、generator。AST运行的三个阶段如下图所示。如果我们要使用babel,插入一段配置代码,应该如何实现解析器(parser)第一步:读取配置文件代码,生成AST抽象语法树letconfigJsData=fs.readFileSync(configJsPath,"utf8");然后从配置文件代码树生成AST抽象语法constparser=require("@babel/parser");letconfigJsTree=parser.parse(`${configJsData}`,{sourceType:"module",plugins:["jsx","flow",],});configJsTree是我们的AST。增加sourceType:"module"配置属性,让babel支持解析导出导入转换(traverse)转换(traverse)阶段,也就是遍历整个AST抽象语法树,找到指定位置,然后插入对应的配置代码。代码如下:consttraverse=require("@babel/traverse").default;traverse(configJsTree,{ObjectProperty(path){//插入配置文件代码},});我们使用@babel/traverse的遍历方法来遍历整个AST中ObjectProperty的作用是在遍历AST的过程中识别所有的Object对象,因为我们要在一个Object对象中插入配置代码,所以我们使用对象属性。如果要将配置插入到数组中,请使用ArrayExpression。然后我们开始插入配置代码,将代码{key:"testPath",icon:HomeOutlined,exact:true,}插入到如下位置。我们需要在traverse的ObjectProperty中搜索位置插入代码。首先,我们需要找到key:'home'的位置代码如下:traverse(configJsTree,{ObjectProperty(path){if(path.node.key.name==="key"&&path.node.value.value==="home"){//这是key的位置:'home'}},});通过path.node.key.name和path.node.value.value找到属性为key,对象值为home的Object对象,找到位置后开始插入代码traverse(configJsTree,{ObjectProperty(path){//在配置文件中搜索并确定对象键的位置:“home”parent.properties.forEach(e=>{if(e.key.name==="children"){//找到子属性}})}},});通过path.parent.properties找到对象的parent,然后遍历parent下的所有属性,找到属性children。这就是我们要插入的地方。接下来我们需要构造要插入的数据{key:"testPath",icon:HomeOutlined,exact:true,}构造数据的代码如下:constt=require("@babel/types");constnewObj=t.objectExpression([t.objectProperty(t.identifier("key"),t.stringLiteral("testPath")),t.objectProperty(t.identifier("icon"),t.identifier("HomeOutlined")),t.objectProperty(t.identifier("exact"),t.booleanLiteral(true)),]);可以看到dentifier用来标识对象的属性,stringLiteral用来标识字符串数据,booleanLiteral用来标识布尔值。这些类型可以在@babel/types的查询中使用。最后一步插入构造好的数据:e.value.elements.push(newObj)完成~!总结所有遍历阶段代码如下:consttraverse=require("@babel/traverse").default;constt=require("@babel/types");traverse(configJsTree,{ObjectProperty(path){//搜索并识别配置文件中的key:"home"对象对象位置if(path.node.key.name==="key"&&path.node.value.value==="home"){path.parent.properties.forEach(e=>{if(e.key.name==="children"){constnewObj=t.objectExpression([t.objectProperty(t.identifier("key"),t.stringLiteral("testPath")),t.objectProperty(t.identifier("icon"),t.identifier("HomeOutlined")),t.objectProperty(t.identifier("exact"),t.booleanLiteral(true)),]);e.value.elements.push(newObj)}})}},});生成(ggenerator)这个阶段就是分解AST抽象语法树生成我们的正则代码constgenerate=require("@babel/generator").default;constresult=generate(configJsTree,{jsescOption:{minimal:true}},"").code;fs.writeFileSync(resultPath,结果);通过@babel/generator将AST抽象代码语法树逆向回原代码,配置jsescOption:{minimal:true}是为了解决unicode汉字乱码的问题至此我们在js配置中插入代码完成文件,最终结果如下:以上就是通过babel操作AST,然后准确插入配置代码的整个过程。完整代码参考:github。等到终点线一切稳定后,我回头看了看女神。她静静地坐着,一边照镜子,一边涂口红。她爱一切。她爱笑。她每周三打篮球。她早上10:30准时到达办公室。她喜欢咖啡。有了奶茶,她的生活每天都是一首歌,而我只会敲代码,加班到腿抽筋。据爆料人说,她已经有男朋友了,高帅富,而我又老又丑,不仅穷还秃头,听说她还很年轻,我32岁,35岁少于3年。时间不多了,怎能留恋人间烟火?女人只会影响我的打字速度。..妈的,我还是默默的守护着她,支持着她,欣赏着她。别打扰我。这是屌丝最高级的告白。只是可惜,我从头到尾都不知道她的名字。我们一句话也没说,我一个人。鲁迅说:“我知道你不是我的花,但能与你绽放擦肩而过,是莫大的荣幸。”.....深夜,在空荡荡的总部大楼里,只是默默地坐在一起,就当我们曾经在一起吧,爱上其他女孩,但谢谢你在每个加班夜给我惊喜,再见我的爱人——————你的小蝌蚪作者:第一个小蝌蚪,公众号:第一个小蝌蚪
