关于javascript:小蝌蚪传记前端实用技巧通过babel精准操作js文件

4次阅读

共计 4073 个字符,预计需要花费 11 分钟才能阅读完成。

明天是暗恋她的第 90 天,但我马上就要失恋了

因为组织架构变动,我要换到一个离她很远的中央

暗恋她的 90 天里,我始终在 997

每天都在跟同类互相残杀

我厌倦了和一群老男人加班的日子

她是这段光明工夫里,惟一的光

她曾是年会的女主持

万千男人暗恋的女神,而我只是个加班狗

她身边都是鲜花和掌声

我身边全是抠脚大汉和 LSP

她每天衣着难看的衣服和名牌包包

而我只有一件粑黄色上衣,和一个装电脑的大黑包

我配不上她,但又被她深深的吸引

结婚 7 年来,我每天上班就回家

不抽烟不喝酒不近女色

腾讯男德第一人

当初竟然对她产生了情愫

本认为我很专一,遇见她当前才明确

原来男人真的能够同时爱上好几个女人

离别之前,不晓得要不要跟她表白

如果表白,她肯定会说我是个坏蛋

如果本人长的再难看点,是不是就不必自大了

惋惜没有如果,我是个完满的垃圾

就这样心烦意乱的上线了一版代码,配置文件还批改错了

间接崩出线上大 bug

所有网页全副 404 not found

1000 封报警邮件狂轰滥炸

boss 婉转的发来 1 星绩效的暗示

都要哭了

配置文件这种货色,人工去批改,太容易受情绪影响而改错了

这些反复且易出错的操作,应该用工程化、自动化伎俩去解决

babel 批改 js 配置文件实现原理

残缺代码参考:github。

像那些 js 配置文件,外面可能有很多的非配置代码,而且一次可能要批改好几个文件

比方咱们在前端我的项目,要插入一个页面,须要批改 router、menus 等配置文件,还要手动拷贝页面模板等等

这些高反复机械化操作,人工批改非常容易出错

咱们能够间接用 babel 来操作 AST 形象语法树,通过工程化去精准批改。让 babel 去帮咱们找到指定地位,并正确插入配置代码。咱们在做工程化开发的时候,常常会用到 babel 去操作 AST。

首先咱们理解一下什么是 AST

AST,形象语法树(Abstract Syntax Tree)它是源代码语法结构的一种形象示意。它以树状的模式体现编程语言的语法结构。

咱们应用 babel 来转化和操作 AST,次要分为三个步骤:解析(parser)、转换(traverse)、生成(generator)

操作 AST 三大阶段

如下图,如果咱们想通过 babel,在配置文件外面插入一段配置代码,应该怎么实现呢

解析(parser)

第一步:读取配置文件代码,并生成 AST 形象语法树

let configJsData = fs.readFileSync(configJsPath, "utf8");

而后将配置文件代码生成 AST 形象语法树

const parser = require("@babel/parser");

let configJsTree = parser.parse(`${configJsData}`,{
    sourceType: "module",
    plugins: [
      "jsx",
      "flow",
    ],
  });

configJsTree 就是咱们的 AST 了

加上 sourceType: "module" 这个配置属性,是为了让 babel 反对解析 export 和 import

转换(traverse)

转换(traverse)阶段,就是要遍历整个 AST 形象语法树,找到指定的地位,而后插入对应的配置代码。

代码如下:

const traverse = require("@babel/traverse").default;

traverse(configJsTree, {ObjectProperty(path) {// 插入配置文件代码},
  });

咱们应用 @babel/traverse 的 traverse 办法进行遍历整个 AST

其中 ObjectProperty 的作用是在遍历 AST 过程中,辨认出所有的 Object 对象,因为咱们是要将配置代码插入一个 Object 对象,所以应用的是ObjectProperty。如果要将配置插入数组中,就应用ArrayExpression

而后咱们开始进行配置代码的插入,将代码

{
  key: "testPath",
  icon: HomeOutlined,
  exact: true,
}

插入如下的地位

咱们须要在 traverseObjectProperty进行地位的查找和代码插入

首先咱们要找到 key: 'home' 的地位

代码如下:

traverse(configJsTree, {ObjectProperty(path) {if ( path.node.key.name === "key" && path.node.value.value === "home") {// 这就是 key: 'home' 的地位}
    },
  });

通过 path.node.key.namepath.node.value.value找到对象属性为 key 并且对象值为 home 的 Object 对象

找到地位后开始插入代码

traverse(configJsTree, {ObjectProperty(path) {
      // 搜寻并辨认出配置文件里 key: "home" 这个 object 对象地位
      if (path.node.key.name === "key" && path.node.value.value === "home") {
        path.parent.properties.forEach(e=>{if ( e.key.name === "children") {// 找到 children 属性}
        })
      }
    },
  });

通过 path.parent.properties 找到对象的父级,而后遍历父级下的所有属性,找到 children 这个属性。这就是咱们要插入的地位。

接下来咱们要结构要插入的数据

{
   key: "testPath",
   icon: HomeOutlined,
   exact: true,
}

结构数据的代码如下:

const t = require("@babel/types");

const newObj = 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标识 boolean 值,这些类型都能够在 @babel/types 查问到。

最初一步,将结构好的数据插入:

e.value.elements.push(newObj)

实现~!

将所有 traverse 阶段代码汇总起来如下:

const traverse = require("@babel/traverse").default;
const t = require("@babel/types");

traverse(configJsTree, {ObjectProperty(path) {
      // 搜寻并辨认出配置文件里 key: "home" 这个 object 对象地位
      if (path.node.key.name === "key" && path.node.value.value === "home") {
        path.parent.properties.forEach(e=>{if ( e.key.name === "children") {
            const newObj = 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)
          }
        })
      }
    },
  });

生成(generator)

这个阶段就是把 AST 形象语法树反解,生成咱们惯例的代码

const generate = require("@babel/generator").default;

const result = generate(configJsTree, { jsescOption: { minimal: true} }, "").code;

fs.writeFileSync(resultPath, result);

通过 @babel/generator 将 AST 形象代码语法树反解回原代码,jsescOption: {minimal: true}配置是为了解决中文为 unicode 乱码的问题。

至此咱们就实现了对 js 配置文件插入代码,最终后果如下:

以上就是通过 babel 操作 AST,而后精准插入配置代码的全流程,残缺代码参考:github。

结尾

线上所有都稳固后

回头看了下女神

她正在照镜子涂口红

就静静坐着,都好喜爱好喜爱

她很爱笑、每周三都会去打篮球,早上 10:30 准时到公司、喜爱咖啡和奶茶

她的生存每天都是一首歌

而我只会敲代码,加班加到腿抽筋

据线人说,她曾经有男朋友了,又高又帅又有钱

而我又老又丑、不仅穷还秃

据说她还很年老,而我曾经 32

还有不到 3 年就 35 岁,我的工夫不多了

怎么能眷恋世间烟火呢

女人只会影响我敲代码的速度

哎。。。真该死

我还是默默地守护她、反对她、观赏她吧

不打扰是屌丝最高级的告白

只是惋惜的是

至始至终,我都不晓得她叫什么

咱们从没说过一句话

都是我一个人的独角戏

鲁迅说过:“我晓得妳不是我的花,但能途经妳的盛放,我不胜荣幸”

。。。。。。

深夜空无一人的总部大楼

就这样默默坐在彼此的身边

就当咱们也已经在一起过吧

这次离别,可能就再也见不到了

不晓得妳会不会想起我

也不晓得我会不会爱上别的女孩

然而还是谢谢妳

惊艳了我每个加班的夜晚

goodbye my lover

————— yours 小蝌蚪

作者:第一名的小蝌蚪,公众号:第一名的小蝌蚪

正文完
 0