我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

通过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插入配置的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

编程热搜

目录