如何从package.json提取依赖构建项目逻辑树?定制类npm ls工具
实现自定义的npm ls风格依赖树工具(带过滤功能)
核心背景与需求回顾
我们拥有多个不同项目,分析每个项目的依赖往往难度大、耗时久。开发者或团队接手新项目时,需花费大量时间调研依赖构成。
需求:实现一个类似npm ls命令的解决方案,该工具可从package.json获取依赖并构建项目逻辑树,且需具备过滤功能。
实现思路
我刚好在团队里解决过类似的多项目依赖分析问题,核心逻辑拆解为三步:
- 读取目标项目的
package.json,提取生产/开发依赖集合 - 构建结构化的依赖树形数据,方便后续处理
- 提供灵活的过滤规则(按名称模糊匹配、依赖类型筛选等)
完整代码实现(Node.js)
用Node.js实现最适配npm生态,代码简洁易扩展,步骤如下:
1. 初始化工具项目
mkdir dep-tree-analyzer && cd dep-tree-analyzer npm init -y
2. 编写核心工具代码(index.js)
const fs = require('fs').promises; const path = require('path'); const minimist = require('minimist'); // 解析命令行参数,需先安装:npm i minimist // 读取目标项目的package.json并提取依赖 async function getProjectDependencies(projectPath) { try { const pkgFilePath = path.resolve(projectPath, 'package.json'); const pkgContent = await fs.readFile(pkgFilePath, 'utf8'); const pkg = JSON.parse(pkgContent); return { prod: pkg.dependencies || {}, dev: pkg.devDependencies || {} }; } catch (err) { console.error(`读取package.json失败: ${err.message}`); process.exit(1); } } // 构建基础依赖树结构 function buildDependencyTree(deps, type) { return Object.entries(deps).map(([name, version]) => ({ name, version, type, // 如需深度遍历嵌套依赖,可在此添加递归逻辑读取子依赖的package.json // children: await getNestedDependencies(name, version) })); } // 实现过滤逻辑 function filterDependencyTree(tree, filterOpts) { let filteredTree = [...tree]; // 按依赖类型过滤(prod/dev二选一) if (filterOpts.type) { filteredTree = filteredTree.filter(item => item.type === filterOpts.type); } // 按名称模糊匹配过滤(不区分大小写) if (filterOpts.name) { const matchRegex = new RegExp(filterOpts.name, 'i'); filteredTree = filteredTree.filter(item => matchRegex.test(item.name)); } return filteredTree; } // 格式化输出为类似npm ls的树形字符串 function formatTreeToPrintable(tree, indentLevel = 0) { let output = ''; const indentStr = ' '.repeat(indentLevel); tree.forEach((item, index) => { const branchSymbol = index === tree.length - 1 ? '└─' : '├─'; output += `${indentStr}${branchSymbol} ${item.name}@${item.version} (${item.type})\n`; // 递归格式化嵌套子依赖(如果有) if (item.children?.length) { output += formatTreeToPrintable(item.children, indentLevel + 1); } }); return output; } // 主执行函数 async function main() { const args = minimist(process.argv.slice(2)); const targetPath = args.path || process.cwd(); // 默认当前目录 const filterOptions = { type: args.type, // 可选值:prod/dev name: args.filter // 模糊匹配关键词 }; // 获取依赖集合 const { prod, dev } = await getProjectDependencies(targetPath); // 构建完整依赖树 let fullTree = []; fullTree.push(...buildDependencyTree(prod, 'prod')); fullTree.push(...buildDependencyTree(dev, 'dev')); // 应用过滤规则 const filteredTree = filterDependencyTree(fullTree, filterOptions); // 输出结果 console.log(`\n项目依赖树(路径:${targetPath}):\n`); console.log(formatTreeToPrintable(filteredTree)); } // 启动工具 main();
3. 安装依赖
npm i minimist
使用说明
运行工具时可传入以下参数:
--path <项目路径>:指定要分析的项目目录(默认当前目录)--type <prod/dev>:仅显示生产依赖或开发依赖--filter <关键词>:模糊匹配依赖名称(不区分大小写)
示例命令
# 分析当前项目的所有依赖 node index.js # 只查看生产依赖 node index.js --type prod # 过滤名称包含"react"的依赖 node index.js --filter react # 分析指定项目的开发依赖,且筛选包含"webpack"的项 node index.js --path ../my-vue-project --type dev --filter webpack
扩展优化建议
- 深度遍历嵌套依赖:添加递归逻辑读取每个依赖的
package.json,构建完整的嵌套树(完全复刻npm ls的输出) - 导出结构化文件:支持将依赖树导出为JSON/CSV格式,方便后续批量分析
- 全局命令化:将工具配置为全局命令,直接在任何项目目录运行
dep-tree
内容的提问来源于stack exchange,提问作者Slava Vasylenko
相关产品推荐
相关产品推荐

