目录
文件夹
选择 CLI 版本
目录
描述
npm 将各种东西放在您的计算机上。 这是它的工作。
本文档将告诉您它将什么放在哪里。
tl;dr
- 本地安装(默认):将东西放在当前包根目录的
./node_modules
中。 - 全局安装(使用
-g
):将东西放在 /usr/local 或节点安装的任何地方。 - 如果您要
require()
它,则将其本地安装。 - 如果您要在命令行上运行它,则将其全局安装。
- 如果您两者都需要,则将它安装在两个地方,或者使用
npm link
。
前缀配置
prefix
配置 默认设置为节点安装的位置。 在大多数系统上,这是 /usr/local
。 在 Windows 上,它是 %AppData%\npm
。 在类 Unix 系统上,它向上提升一级,因为节点通常安装在 {prefix}/bin/node
而不是 {prefix}/node.exe
。
当设置了 global
标志时,npm 将东西安装到这个前缀中。 当没有设置它时,它使用当前包的根目录,或者如果不在包中,则使用当前工作目录。
节点模块
包被放到 prefix
下的 node_modules
文件夹中。 当本地安装时,这意味着您可以 require("packagename")
来加载它的主模块,或者 require("packagename/lib/path/to/sub/module")
来加载其他模块。
类 Unix 系统上的全局安装到 {prefix}/lib/node_modules
。 Windows 上的全局安装到 {prefix}/node_modules
(即,没有 lib
文件夹)。
作用域包的安装方式相同,只是它们在相关 node_modules
文件夹的子文件夹中分组在一起,该子文件夹的名称由 @ 符号前的作用域前缀决定,例如 npm install @myorg/package
会将包放在 {prefix}/node_modules/@myorg/package
中。 有关更多详细信息,请参阅 scope
。
如果您希望 require()
一个包,那么请将其本地安装。
可执行文件
在全局模式下,可执行文件被链接到类 Unix 系统上的 {prefix}/bin
,或者直接链接到 Windows 上的 {prefix}
。 确保该路径在您的终端的 PATH
环境中,以便运行它们。
在本地模式下,可执行文件被链接到 ./node_modules/.bin
,以便它们可以供通过 npm 运行的脚本使用。 (例如,以便在运行 npm test
时,测试运行器位于路径中)。
手册页
在全局模式下,手册页被链接到 {prefix}/share/man
。
在本地模式下,不会安装手册页。
Windows 系统上不会安装手册页。
缓存
参阅 npm cache
。 缓存文件存储在 Posix 上的 ~/.npm
或 Windows 上的 %LocalAppData%/npm-cache
中。
这由 cache
配置 参数控制。
临时文件
临时文件默认存储在由 tmp
配置 指定的文件夹中,该文件夹默认为 TMPDIR、TMP 或 TEMP 环境变量,或者类 Unix 系统上的 /tmp
和 Windows 上的 c:\windows\temp
。
临时文件为程序的每次运行在此根目录下分配一个唯一的文件夹,并在成功退出时删除。
更多信息
当本地安装时,npm 首先尝试找到一个合适的 prefix
文件夹。 这样做是为了使 npm install [email protected]
安装到您包的合理根目录,即使您碰巧 cd
进入其他文件夹。
从 $PWD 开始,npm 将向上遍历文件夹树,检查是否存在包含 package.json
文件或 node_modules
文件夹的文件夹。 如果找到这样的东西,那么它被视为运行 npm 命令的有效“当前目录”。 (此行为受 git 的 .git-文件夹查找逻辑的启发,类似于在工作目录中运行 git 命令时)。
如果找不到包根目录,则使用当前文件夹。
当您运行 npm install [email protected]
时,该包会被加载到缓存中,然后解压到 ./node_modules/foo
。 之后,foo 的任何依赖项也会以类似的方式解压到 ./node_modules/foo/node_modules/...
。
任何 bin 文件都会被符号链接到 ./node_modules/.bin/
,以便 npm 脚本在需要时可以找到它们。
全局安装
如果 global
配置 设置为 true,则 npm 将“全局”安装包。
对于全局安装,包的安装方式大致相同,但使用上述文件夹。
循环、冲突和文件夹简洁性
循环处理利用了 Node 模块系统的一个特性,它会向上遍历目录寻找 node_modules
文件夹。因此,在每个阶段,如果某个包已安装在祖先 node_modules
文件夹中,那么它就不会安装在当前位置。
考虑上面的情况,其中 foo -> bar -> baz
。 想象一下,除了这些之外,baz 还依赖于 bar,所以您将拥有:foo -> bar -> baz -> bar -> baz ...
。 但是,由于文件夹结构是:foo/node_modules/bar/node_modules/baz
,所以无需在 .../baz/node_modules
中放置另一个 bar 的副本,因为当 baz 调用 require("bar")
时,它会获取安装在 foo/node_modules/bar
中的副本。
此快捷方式仅在多个嵌套的 node_modules
文件夹中安装的是完全相同的版本时使用。 仍然可以有 a/node_modules/b/node_modules/a
,如果两个“a”包是不同的版本。 但是,如果没有重复安装完全相同的包多次,那么无限循环总是可以避免的。
另一个优化可以通过在尽可能高的级别(低于本地化的“目标”文件夹)安装依赖项来实现(提升)。 从版本 3 开始,npm 默认提升依赖项。
示例
考虑以下依赖项图
foo| +-- [email protected]| `-- asdf@*`-- bar
在这种情况下,我们可能会期望一个像这样的文件夹结构(所有依赖项都提升到尽可能高的级别)
foo+-- node_modules+-- blerg (1.2.5) <---[A]+-- bar (1.2.3) <---[B]| +-- node_modules| +-- baz (2.0.2) <---[C]+-- asdf (2.3.4)+-- baz (1.2.3) <---[D]+-- quux (3.2.0) <---[E]
由于 foo 直接依赖于 [email protected]
和 [email protected]
,因此它们安装在 foo 的 node_modules
文件夹中。
即使 blerg 的最新版本是 1.3.7,foo 对版本 1.2.5 也有特定的依赖项。 因此,它会安装在 [A] 中。 由于 blerg 的父安装满足了 bar 对 [email protected]
的依赖关系,因此它不会在 [B] 下安装另一个副本。
Bar [B] 也依赖于 baz 和 asdf。 因为它依赖于 [email protected]
,所以它不能重用安装在父 node_modules
文件夹 [D] 中的 [email protected]
,并且必须安装自己的副本 [C]。 为了最大程度地减少重复,npm 默认情况下会将依赖项提升到顶层,因此 asdf 安装在 [A] 下。
在 bar 下,baz -> quux -> bar
依赖关系创建了一个循环。 但是,由于 bar 已经在 quux 的祖先 [B] 中,因此它不会将另一个 bar 的副本解压到该文件夹中。 同样,quux 的 [E] 文件夹树是空的,因为其对 bar 的依赖关系由安装在 [B] 中的父文件夹副本满足。
要以图形方式了解安装位置,请使用 npm ls
。
发布
发布时,npm 将查看 node_modules
文件夹。 如果其中的任何项目不在 bundleDependencies
数组中,那么它们将不会包含在包 tarball 中。
这允许包维护者在本地安装所有依赖项(以及开发依赖项),但仅重新发布那些在其他地方找不到的项目。 有关更多信息,请参见 package.json
。