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

通过babel操作AST精准插入配置代码全流程的更多相关文章

  1. android – bundling failed:错误:插件0提供了“default”的无效属性

    我正在尝试使用此命令在我的AVD上运行react本机应用程序:但得到以下错误:.babelrc:package.json:我正在使用Windows,node.jsv8.11.3&反应原生v0.55.4我已经尝试过在互联网上推荐的所有内容,但仍然没有运气.如果有人可以提供帮助,真的很感激.解决方法这是babel-preset-react-native中的错误设置版本:

  2. 详解Webpack+Babel+React开发环境的搭建的方法步骤

    本篇文章主要介绍了详解Webpack+Babel+React开发环境的搭建的方法步骤,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. 详解webpack2+node+react+babel实现热加载(hmr)

    这篇文章主要介绍了详解webpack2+node+react+babel实现热加载(hmr) ,非常具有实用价值,需要的朋友可以参考下

  4. Babel自动生成Attribute文档实现详解

    这篇文章主要为大家介绍了Babel自动生成Attribute文档实现示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  5. 让nodeJS支持ES6的词法----babel的安装和使用方法

    这篇文章主要介绍了让nodeJS支持ES6的词法----babel的安装和使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

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

    这篇文章主要为大家介绍了通过babel操作AST精准插入配置代码的全流程,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步

  7. react源码层深入刨析babel解析jsx实现

    同作为MVVM框架,React相比于Vue来讲,上手更需要JavaScript功底深厚一些,本系列将阅读React相关源码,从jsx -> VDom -> RDOM等一些列的过程,将会在本系列中一一讲解

  8. Node.js基础模块babel使用详解

    这篇文章主要介绍了Node.js基础模块babel使用详解,babel是由一系列的组件构成,所以我们在开发过程中,要从自行配置组件来开始使用babel的功能

  9. Vue编程三部曲之将template编译成AST示例详解

    这篇文章主要为大家介绍了Vue编程三部曲之将template编译成AST示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. Vue编译器AST抽象语法树源码分析

    这篇文章主要为大家介绍了Vue编译器AST抽象语法树源码分析详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部