如何生成含导出项类型的JavaScript细粒度依赖JSON报告
实现ES6+ JS文件依赖及导出项的精准JSON报告方案
要生成你需要的精准依赖报告,可以用Node.js结合Babel的AST解析工具实现,直接扫描指定目录、解析每个JS文件的导入导出逻辑,整理成目标格式的JSON。
步骤1:安装依赖
首先安装解析AST所需的核心包:
npm install @babel/parser @babel/traverse @babel/types
步骤2:编写扫描脚本(命名为dependency-scanner.js)
const fs = require('fs').promises; const path = require('path'); const parser = require('@babel/parser'); const traverse = require('@babel/traverse').default; const t = require('@babel/types'); // 目标扫描目录(按需修改) const TARGET_DIR = path.resolve(__dirname, './js'); // 输出报告路径 const OUTPUT_FILE = path.resolve(__dirname, './dependency-report.json'); /** * 获取单个JS文件的导出项及类型 * @param {string} filePath 文件绝对路径 * @returns {Array<{name: string, type: string}>} 导出项列表 */ async function getExportsFromFile(filePath) { const code = await fs.readFile(filePath, 'utf8'); const ast = parser.parse(code, { sourceType: 'module', plugins: ['jsx'] // 若用TS可添加'typescript'插件 }); const exportsList = []; traverse(ast, { // 处理直接导出的函数/变量 ExportNamedDeclaration(path) { const declaration = path.node.declaration; // 函数导出 if (t.isFunctionDeclaration(declaration)) { exportsList.push({ name: declaration.id.name, type: 'function' }); } // 变量导出(区分常量/数组/对象) else if (t.isVariableDeclaration(declaration)) { declaration.declarations.forEach(declarator => { let type = 'constant'; if (t.isArrayExpression(declarator.init)) type = 'array'; if (t.isObjectExpression(declarator.init)) type = 'object'; exportsList.push({ name: declarator.id.name, type: declaration.kind === 'const' ? type : 'variable' }); }); } }, // 处理批量导出的标识符 ExportSpecifier(path) { exportsList.push({ name: path.node.exported.name, type: 'unknown' // 需精准类型可递归解析源文件,此处简化处理 }); } }); return exportsList; } /** * 获取单个JS文件的导入依赖信息 * @param {string} filePath 文件绝对路径 * @returns {Array<{source: string, imports: Array<string>}>} 导入依赖列表 */ async function getImportsFromFile(filePath) { const code = await fs.readFile(filePath, 'utf8'); const ast = parser.parse(code, { sourceType: 'module' }); const importsList = []; traverse(ast, { ImportDeclaration(path) { const sourcePath = path.node.source.value; // 只处理本地相对路径依赖(排除第三方包) if (sourcePath.startsWith('./') || sourcePath.startsWith('../')) { const resolvedSource = path.resolve(path.dirname(filePath), sourcePath); const fullSourcePath = resolvedSource.endsWith('.js') ? resolvedSource : `${resolvedSource}.js`; const relativeSource = path.relative(TARGET_DIR, fullSourcePath); // 收集当前文件导入的具体名称 const importedNames = path.node.specifiers .filter(spec => t.isImportSpecifier(spec)) .map(spec => spec.imported.name); importsList.push({ source: relativeSource, imports: importedNames }); } } }); return importsList; } /** * 扫描目录生成最终依赖报告 */ async function generateDependencyReport() { const report = {}; // 递归遍历目录下所有JS文件 async function traverseDir(dir) { const entries = await fs.readdir(dir, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.resolve(dir, entry.name); if (entry.isDirectory()) { await traverseDir(fullPath); } else if (entry.isFile() && entry.name.endsWith('.js')) { const relativePath = path.relative(TARGET_DIR, fullPath); const imports = await getImportsFromFile(fullPath); if (imports.length === 0) continue; report[relativePath] = {}; // 匹配每个依赖文件中当前文件实际导入的导出项 for (const imp of imports) { const depFilePath = path.resolve(TARGET_DIR, imp.source); try { const depExports = await getExportsFromFile(depFilePath); const matchedExports = depExports.filter(exp => imp.imports.includes(exp.name)); report[relativePath][imp.source] = { exports: matchedExports }; } catch (err) { console.warn(`无法解析依赖文件: ${depFilePath}`, err.message); report[relativePath][imp.source] = { exports: [] }; } } } } } await traverseDir(TARGET_DIR); await fs.writeFile(OUTPUT_FILE, JSON.stringify(report, null, 2), 'utf8'); console.log(`依赖报告已生成:${OUTPUT_FILE}`); } // 执行扫描 generateDependencyReport().catch(err => console.error('生成报告失败:', err));
步骤3:运行脚本
在终端执行:
node dependency-scanner.js
关键说明
- 脚本仅扫描本地相对路径的JS依赖,自动排除第三方包
- 支持识别函数、常量、数组、对象等常见导出类型
- 若项目使用JSX或TypeScript,可在AST解析配置中添加对应插件
- 生成的JSON结构完全匹配你要求的格式,仅保留实际导入的导出项,无冗余信息
内容的提问来源于stack exchange,提问作者Zarty
相关产品推荐
相关产品推荐

