通过babel操作AST精准插入配置代码全流程

 更新时间:2022年02月08日 09:42:32   作者:厦门在乎科技  
这篇文章主要为大家介绍了通过babel操作AST精准插入配置代码的全流程,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步

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

像那些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,然后精准插入配置代码的全流程。

更多关于babel操作AST插入配置的资料请关注脚本之家其它相关文章!

相关文章

  • JS实现跟随鼠标立体翻转图片的方法

    JS实现跟随鼠标立体翻转图片的方法

    这篇文章主要介绍了JS实现跟随鼠标立体翻转图片的方法,涉及javascript操作图片翻转的相关技巧,非常具有实用价值,需要的朋友可以参考下
    2015-05-05
  • JavaScript语言中的Literal Syntax特性分析

    JavaScript语言中的Literal Syntax特性分析

    JavaScript语言中的Literal Syntax特性分析...
    2007-03-03
  • js实现base64、url和blob之间相互转换的3种方式举例

    js实现base64、url和blob之间相互转换的3种方式举例

    在JavaScript中将图片的绝对路径转换为base64字符串或blob对象,是常见的图片上传前的预处理步骤,这篇文章主要介绍了js实现base64、url和blob之间相互转换的3种方式,需要的朋友可以参考下
    2025-04-04
  • JavaScript中运算符与数组扩展详细讲解

    JavaScript中运算符与数组扩展详细讲解

    这篇文章主要介绍了JavaScript中运算符与数组扩展方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2022-11-11
  • JavaScript事件机制的剖析与优化详解

    JavaScript事件机制的剖析与优化详解

    在现代前端开发中,JavaScript事件处理是一个至关重要的部分,它能够使网页与用户交互,实现丰富的交互体验,然而,对JavaScript事件机制的深入理解是开发者成为优秀前端工程师的关键所在,本文将全面剖析JavaScript事件机制,需要的朋友可以参考下
    2023-12-12
  • JavaScript实现的商品抢购倒计时功能示例

    JavaScript实现的商品抢购倒计时功能示例

    这篇文章主要介绍了JavaScript实现的商品抢购倒计时功能,可实现分秒级别的实时显示倒计时效果,涉及js日期时间计算与页面元素动态操作相关技巧,需要的朋友可以参考下
    2017-04-04
  • 10个在JavaScript开发中常遇到的BUG

    10个在JavaScript开发中常遇到的BUG

    给大家详细着整理了在JavaScript开发中大家经常遇到的BUG和问题,需要的朋友参考学习下吧。
    2017-12-12
  • 微信小程序之仿微信漂流瓶实例

    微信小程序之仿微信漂流瓶实例

    这篇文章主要介绍了微信小程序之仿微信漂流瓶实例,非常具有实用价值,需要的朋友可以参考下。
    2016-12-12
  • ajax中get和post的说明及使用与区别

    ajax中get和post的说明及使用与区别

    对付乱码我都是用过滤器做字符编码过滤的,Get方法过滤器监听不到,所以我一直喜欢使用Post方法,下面对Ajax Get和Post方法做一对比,需要了解的朋友可以 参考下
    2012-12-12
  • 纯前端使用插件pdfjs实现将pdf转为图片的步骤

    纯前端使用插件pdfjs实现将pdf转为图片的步骤

    这篇文章主要介绍了纯前端使用插件pdfjs实现将pdf转为图片的步骤,在实现过程中遇到了跨域问题,后台设置跨域但前端配置无效,最终采用后台返回PDF的base64格式,通过PDF.js将base64转换为二进制数据加载PDF,需要的朋友可以参考下
    2025-01-01

最新评论