背景
在开发物料平台的过程中, 为了提升物料开发的效率, 对 api 接口做了约定, 将物料用到的接口都配置到同一个 js 文件内.按照变量名划分.
1 | const mApi = { |
为了减少操作, 打算根据这个文件自动配置代理.
一个搭建平台一般有后台(一般放在公司的管理系统域名下)和 M 站两部分, 所以这两部分接口需要分别指向不同的域名.
也就是获得下面的代码:
1 | export default { |
首先想到的方法是正则提取, 但大家在代码里如何配置路由和参数不太可控, 可能出现提取错误, 也不容易判断哪个接口所属那个 api 下.
因此采用 AST 解析的方式, 更准确也更优雅的提取, 也对物料开发有更少的限制.
依赖的工具
babel 是一个前端工程中很常用的工具, 其作用就是用将使用未来新语法的代码解析成 AST (Abstract Syntax Tree 抽象语法树), 然后转换成已经被浏览器兼容的语法, 再将其生成代码.
而 babel 是由多个工具组成的, 本次实现这个功能用到了以下工具:
- parser (AST 解析器)
- generator (代码生成器)
- traverse (转换器)
- types AST (节点类型)
解析
将代码解析成 AST 树, 很简单:
1 | const parser = require("@babel/parser"); |
遍历 AST, 找到配置 ajax 请求 url 的地方, 将存储到对应的数组中
1 | const traverse = require("@babel/traverse").default; |
这里存在一个问题. @babel/traverse
的 enter 方法提供的回调参数里只能拿到 当前 node 和 parent node, 因此无法直接得知它属于哪个 api 对象.
为了做出判断, 维护一个 parentChain
栈, 记录深度优先遍历过程中的所有父级节点, 在判断时就可以根据这个栈找到它的祖先节点.
创建代码
拿到 mApiList
和 adminApiList
数组后, 就可以生成配置了.
这一步拼接字符串也可以实现, 但为了更好的理解 AST, 就遍历数组再次创建一个 AST, 使用 @babel/generator
生成 JS 代码.
1 | const generator = require("@babel/generator").default; |
得到源码后, 将其写入到 js 文件.
1 | fs.writeFileSync( |
这样就得到了一个 export 开头提到的代理配置列表 js 文件, 将其导入到 webpack 的 proxy 配置即可.