记下使用 nodejs 收集vue、umi项目前端路由地址
# 背景
公司某项目需要提供一份项目页面所有可访问URL访问测试页面功能。
# 实现思路
比较原始的办法是手动去打开页面,但是效率太低了,而且需要熟悉项目的权限防止漏掉页面。
所以这里使用直接读取项目路由文件的方式直接解析路由对象来获取到所有的可访问URL。
# 具体方案
指定项目中路由文件所在目录,遍历目录中的文件,读取文件内容并进行截取,把定义路由的数组单独抽取出来。将抽取出来的路由数组放入js虚拟机中执行获取返回结果,循环路由数组获取到所有的路由访问path。
下面是参考代码(基于vue及umi项目):
const vm = require("vm");
const fs = require("fs");
const path = require("path");
const dirPath = ""; // 项目路由文件目录
function walkDir(dir, callback) {
fs.readdirSync(dir).forEach((file) => {
let fullPath = path.join(dir, file);
let stat = fs.lstatSync(fullPath);
if (stat.isDirectory()) {
walkDir(fullPath, callback);
} else if (stat.isFile()) {
callback(fullPath);
}
});
}
function routesCollect() {
let allRoutes = [];
walkDir(dirPath, (filePath) => {
// 读取路由文件内容
let page = fs.readFileSync(filePath, "utf-8");
let match = page.substring(
page.indexOf("= [") + 2,
page.lastIndexOf("]") + 1
);
if (filePath.indexOf(".ts") != -1) {
match = page.substring(
page.indexOf(" [") + 1,
page.lastIndexOf("]") + 1
);
}
let rtArr = match.replace(/\/\/.*$/gm, "").replace(/\s+/g, "");
if (filePath.indexOf(".ts") == -1) {
rtArr = rtArr.replace(/component.*$/gm, "");
}
const script = new vm.Script(rtArr);
const routeArr = script.runInThisContext();
allRoutes.push(...routeArr);
});
let allrts = [];
allRoutes.map((r) => {
if (r.children || r.routes) {
r.children = r.children || r.routes;
r.children.map((c) => {
if (c.path) {
if (c.path.startsWith("/")) {
!allrts.includes(c.path) && allrts.push(c.path);
} else {
!allrts.includes(r.path + "/" + c.path) &&
allrts.push(r.path + "/" + c.path);
}
}
});
} else {
if (!allrts.includes(r.path)) {
allrts.push(r.path);
}
}
});
fs.writeFileSync("routes.json", JSON.stringify(allrts));
}
routesCollect();
# 使用方法
指定项目路由文件的存放路径 dirPath
,使用 nodejs
执行脚本,可在同级目录得到存放所有路由信息的 routes.json
。
# 问题处理
脚本主要是遍历vue/react项目的路由文件,抽取路由定义代码之后使用js虚拟机执行获取路由对象来得到所有可访问地址,如果项目对路由定义进行一些额外的修改需要根据实际情况进行修改。
代码中一些无关内容可以通过正则匹配方式进行剔除:
- 去除注释:
replace(/\/\/.*$/gm, "")
- 去除组件:
replace(/component.*$/gm, "")