使用 npm 的 `ls` 命令来获得乐趣和洞察力

2025-06-04

使用 npm 的 `ls` 命令来获得乐趣和洞察力

我对 JavaScript 和 Node.js 依赖树最大的问题之一是......从来都不是很容易理解你得到了什么以及你可以做什么来补救。

npm ls最近我一直在探索API,并想分享一些我发现的东西,我希望在过去几年里了解它们!

简介npm ls

如果您不熟悉npm ls,它是 npm CLI 中的一个命令,用于列出已安装到 的依赖项。此外,如果 中解析的依赖关系树不是应该从 中解析的依赖关系树,node_modules它将返回非零退出代码node_modulespackage.json

npm ls这是我的一个项目good-first-issue的简单示例

good-first-issue@0.24.0 /Users/cyren/GitHub/good-first-issue
├─┬ @octokit/rest@16.17.0
│ ├─┬ @octokit/request@2.4.1
│ │ ├─┬ @octokit/endpoint@3.1.3
│ │ │ ├── deepmerge@3.2.0
│ │ │ ├── is-plain-object@2.0.4 deduped
│ │ │ ├── universal-user-agent@2.0.3 deduped
│ │ │ └── url-template@2.0.8 deduped
│ │ ├── deprecation@1.0.1
│ │ ├─┬ is-plain-object@2.0.4
│ │ │ └── isobject@3.0.1
│ │ ├── node-fetch@2.3.0
│ │ ├─┬ once@1.4.0
│ │ │ └── wrappy@1.0.2
│ │ └── universal-user-agent@2.0.3 deduped
│ ├── before-after-hook@1.4.0
│ ├── btoa-lite@1.0.0
│ ├── lodash.get@4.4.2
│ ├── lodash.set@4.3.2
│ ├── lodash.uniq@4.5.0
│ ├── octokit-pagination-methods@1.1.0
│ ├─┬ universal-user-agent@2.0.3
│ │ └─┬ os-name@3.0.0
│ │ ├── macos-release@2.0.0
│ │ └─┬ windows-release@3.1.0
│ │ └─┬ execa@0.10.0
│ │ ├── cross-spawn@6.0.5 deduped
│ │ ├── get-stream@3.0.0 deduped
│ │ ├── is-stream@1.1.0 deduped
│ │ ├── npm-run-path@2.0.2 deduped
│ │ ├── p-finally@1.0.0 deduped
│ │ ├── signal-exit@3.0.2 deduped
│ │ └── strip-eof@1.0.0 deduped
│ └── url-template@2.0.8
├─┬ boxen@3.0.0
│ ├─┬ ansi-align@3.0.0
│ │ └── string-width@3.1.0 deduped
│ ├── camelcase@5.2.0
│ ├── chalk@2.4.2 deduped
│ ├── cli-boxes@2.0.0
│ ├─┬ string-width@3.1.0
│ │ ├── emoji-regex@7.0.3
│ │ ├── is-fullwidth-code-point@2.0.0
│ │ └── strip-ansi@5.1.0 deduped
│ ├─┬ term-size@1.2.0
│ │ └─┬ execa@0.7.0
│ │ ├─┬ cross-spawn@5.1.0
│ │ │ ├─┬ lru-cache@4.1.5
│ │ │ │ ├── pseudomap@1.0.2
│ │ │ │ └── yallist@2.1.2
│ │ │ ├── shebang-command@1.2.0 deduped
│ │ │ └── which@1.3.1 deduped
│ │ ├── get-stream@3.0.0
│ │ ├── is-stream@1.1.0
│ │ ├─┬ npm-run-path@2.0.2
│ │ │ └── path-key@2.0.1 deduped
│ │ ├── p-finally@1.0.0
│ │ ├── signal-exit@3.0.2
│ │ └── strip-eof@1.0.0
│ └─┬ widest-line@2.0.1
│ └─┬ string-width@2.1.1
│ ├── is-fullwidth-code-point@2.0.0 deduped
│ └─┬ strip-ansi@4.0.0
│ └── ansi-regex@3.0.0
├─┬ chalk@2.4.2
│ ├─┬ ansi-styles@3.2.1
│ │ └─┬ color-convert@1.9.3
│ │ └── color-name@1.1.3
│ ├── escape-string-regexp@1.0.5
│ └─┬ supports-color@5.5.0
│ └── has-flag@3.0.0
├── commander@2.19.0
├─┬ inquirer@6.2.2
│ ├── ansi-escapes@3.2.0
│ ├── chalk@2.4.2 deduped
This command's output is 1339 lines long. See the full output in gist form here: https://gist.github.com/bnb/043d9d88820e3a5f31f0411e6ead141a
view raw gistfile1.txt hosted with ❤ by GitHub

此命令的输出长达 1339 行。完整输出的 gist 格式请见此处(它太大了,不太适合放在这篇文章里!):https://gist.github.com/bnb/043d9d88820e3a5f31f0411e6ead141a

只需运行npm install,我就能得到总共 1337 个模块。没错,这就是实际数量,加上模块的电流package.json——我和你一样惊讶!

deduped如果你滚动浏览该列表,你会看到末尾有一行带有。这意味着 npm 能够解析该模块的一个版本,该版本满足需要安装的多个依赖项的要求。使用我的第一个grep命令 ( grep deduped npm-ls.txt -c),我能够找到已重复数据删除的模块总数:

我的终端显示原始“grep deduped npm-ls.txt -c”的输出为 532,表示已成功删除 532 个模块

事实证明,在 1337 个模块中,有 532 个已成功去重。值得注意的是,每一行都带有 的deduped模块都不需要安装,因为它是通过另一个标记为的路径安装的deduped。根据此上下文,我们知道总共安装了 805 个模块。

裸露 vs. --productionvs.--development

能够更好地理解我们的依赖树真是太棒了!也就是说,它npm ls本身就能告诉你整个node_modules目录的当前状态……如果你关心哪些东西会投入生产,那么最好将那些即将投入生产的依赖项与 devDependencies 分开,后者只是为了让你作为开发人员的工作更轻松。

npm ls --production同一个项目上运行,我们得到一个...小得多的结果:

这次,npm ls显示我们只有 110 个模块。如果我们deduped使用稍微修改过的grep命令检查,我们会发现有 21 个依赖项被重复数据删除了。在重复数据删除之前,npm ls --productiongood-first-issue 中的模块数量与 的裸版本相比减少了 12 倍npm ls;在重复数据删除之后,npm ls --productiongood-first-issue 中的模块数量与 的裸版本相比减少了 9 倍npm ls

了解引入到生产环境中的模块非常重要,而且非常有价值。但是,如果您还想了解开发依赖项怎么办?

幸运的是,npm ls它还提供了一个--development标志,允许您了解仅在开发中使用的依赖项。还有一些更高级的用例,其中大多数旨在帮助像您和我这样的开发人员了解本地正在使用的内容以及如何优化。

用于查找如何将特定模块引入到项目中

的一个巧妙功能npm ls是能够将包名称作为参数传递给命令。例如,如果我想graceful-fs在依赖关系树中查找所有实例,我可以运行npm ls graceful-fs以下命令,它将输出以下内容:

我的 good-first-issue 项目中原始 `npm ls graceful-fs` endraw 的终端输出。展示此示例的目的是提供一个示例,说明在实际项目中,原始 `npm ls <package>` endraw 命令可以预期什么样的输出。

对我来说,这是一个非常出色的功能!我花了很多时间探索 Node.js 和 JavaScript 模块生态系统中的安全空间。这个功能对我来说非常有用,因为最常见的安全漏洞来源之一是通过依赖关系树(而不是直接在 中引入package.json)。能够显示已知易受攻击的特定模块的所有实例非常有用,而这个命令让这一切变得非常简单。

JavaScript 项目的 CI/CD 使用

在Node.js 包维护团队最近的讨论中,npm ls提出在 CI/CD 环境中使用是一种可能的最佳实践,以确保 npm 解析的依赖树完全有效并且能够运行。

我之前没想过这个,但这确实是一个非常好的保障措施。由于npm ls如果依赖关系树无效,它会以非零的退出码退出,因此该命令实际上成为了 CI/CD 中的一项零投入保障措施,以确保依赖关系树能够按照预期的方式进行解析。此外,这个想法可以与npm ls --production生产构建结合使用!

npm ls这几天我一直在探索,所以想和大家分享一下我的知识。我完全相信这个命令还有很多实用功能我还没发现,如果你有什么建议,我非常乐意听听!另外,我很想知道你是否打算开始使用npm ls更多命令,以及你打算如何使用它!💖

文章来源:https://dev.to/bnb/using-npms-ls-command-for-fun-and-insight-5he7
PREV
Node.js 中的设计模式:第 2 部分
NEXT
我的🔥首次参加 TC39 的经历