前端通过babel精准操作js文件技巧

目录
文章目录隐藏
  1. babel 修改 js 配置文件实现原理
  2. 操作 AST 三大阶段

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

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

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

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

我们可以直接用 babel 来操作 AST 抽象语法树,通过工程化去精准修改。让 babel 去帮我们找到指定位置,并正确插入配置代码。我们在做工程化开发的时候,经常会用到 babel 去操作 AST。

首先我们了解一下什么是 AST?

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

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

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

操作 AST 三大阶段

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

操作 AST 三大阶段

解析(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,
}

插入如下的位置:

操作 AST 三大阶段

我们需要在traverseObjectProperty进行位置的查找和代码插入。

首先我们要找到key: 'home'的位置。

找到 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 配置文件插入代码,最终结果如下:

js 配置文件代码

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

参考文章:链接

「点点赞赏,手留余香」

2

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
码云笔记 » 前端通过babel精准操作js文件技巧

发表回复