文件夹

npm 使用的文件夹结构

描述

npm 在你的计算机上放置各种东西。 这就是它的工作。

这份文件会告诉你它把什么放在哪里。

tl;dr

  • 本地安装(默认): 将内容放入当前包根目录的 ./node_modules 中。
  • 全局安装(使用 -g): 将东西放在 /usr/local 或安装节点的任何地方。
  • 如果要安装 require(),请安装 locally
  • 如果要在命令行上运行它,请安装它 globally
  • 如果两者都需要,那么在两个地方都安装,或者使用 npm link

前缀配置

prefix 配置默认为安装 node 的位置。 在大多数系统上,这是 /usr/local。 在 Windows 上,它是 %AppData%\npm。 在 Unix 系统上,它是上一级的,因为 node 通常安装在 {prefix}/bin/node 而不是 {prefix}/node.exe

当设置 global 标志时,npm 会将内容安装到此前缀中。 如果未设置,则使用当前包的根目录,如果不在包中,则使用当前工作目录。

Node 模块

包被放到 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}

在本地模式下,可执行文件被链接到 ./node_modules/.bin,以便它们可用于通过 npm 运行的脚本。 (例如,当你运行 npm test 时,测试运行程序将在路径中。)

手册页

在全局模式下,手册页链接到 {prefix}/share/man

在本地模式下,不安装手册页。

手册页未安装在 Windows 系统上。

缓存

npm cache。 缓存文件存储在 Posix 上的 ~/.npm 或 Windows 上的 %AppData%/npm-cache 中。

这由 cache 配置参数控制。

临时文件

临时文件默认存储在 tmp 配置指定的文件夹中,默认为 TMPDIR、TMP 或 TEMP 环境变量,或者 Unix 上的 /tmp 和 Windows 上的 c:\windows\temp

每次运行程序时,都会在此根目录下为临时文件分配一个唯一文件夹,并在成功退出后删除。

更多信息

在本地安装时,npm 首先尝试找到合适的 prefix 文件夹。 这样 npm install foo@1.2.3 将安装到你的包的合理根目录,即使你碰巧将 cd 安装到其他文件夹中。

从 $PWD 开始,npm 将遍历文件夹树,检查包含 package.json 文件或 node_modules 文件夹的文件夹。 如果找到这样的东西,那么为了运行 npm 命令,它被视为有效的 "当前目录"。 (在工作目录中运行 git 命令时,此行为受到 git 的 .git-folder 搜索逻辑的启发并与之类似。)

如果没有找到包根目录,则使用当前文件夹。

当你运行 npm install foo@1.2.3 时,包被加载到缓存中,然后解压到 ./node_modules/foo 中。 然后,任何 foo 的依赖都被类似地解包到 ./node_modules/foo/node_modules/... 中。

任何 bin 文件都符号链接到 ./node_modules/.bin/,以便在必要时可以通过 npm 脚本找到它们。

全局安装

如果 global 配置设置为 true,则 npm 将安装包 "globally"。

对于全局安装,包的安装方式大致相同,但使用上述文件夹。

循环、冲突和文件夹简约

循环使用 node 模块系统的属性处理,它遍历目录查找 node_modules 文件夹。 因此,在每个阶段,如果一个包已经安装在祖级 node_modules 文件夹中,那么它不会安装在当前位置。

考虑上面的情况,其中 foo -> bar -> baz。 想象一下,如果除此之外,baz 还依赖于 bar,那么你将拥有: foo -> bar -> baz -> bar -> baz ...。 但是,由于文件夹结构是: foo/node_modules/bar/node_modules/baz,不需要将 bar 的另一个副本放入 .../baz/node_modules,因为当它调用 require("bar") 时,它将获得安装在 foo/node_modules/bar 中的副本。

只有在多个嵌套的 node_modules 文件夹中安装完全相同的版本时,才使用此快捷方式。 如果两个 "a" 包是不同的版本,仍然可以有 a/node_modules/b/node_modules/a。 但是,如果不多次重复完全相同的包,将始终防止无限倒退。

可以通过在本地化 "target" 文件夹下的最高级别安装依赖来进行另一项优化。

示例

考虑这个依赖图:

foo
+-- blerg@1.2.5
+-- bar@1.2.3
| +-- blerg@1.x (latest=1.3.7)
| +-- baz@2.x
| | `-- quux@3.x
| | `-- bar@1.2.3 (cycle)
| `-- asdf@*
`-- baz@1.2.3
`-- quux@3.x
`-- bar

在这种情况下,我们可能期望这样的文件夹结构:

foo
+-- node_modules
+-- blerg (1.2.5) <---[A]
+-- bar (1.2.3) <---[B]
| `-- node_modules
| +-- baz (2.0.2) <---[C]
| | `-- node_modules
| | `-- quux (3.2.0)
| `-- asdf (2.3.4)
`-- baz (1.2.3) <---[D]
`-- node_modules
`-- quux (3.2.0) <---[E]

由于 foo 直接依赖于 bar@1.2.3baz@1.2.3,因此它们安装在 foo 的 node_modules 文件夹中。

尽管 blerg 的最新版本是 1.3.7,但 foo 对 1.2.5 版本有特定的依赖。 所以,它被安装在 [A]。 由于 blerg 的父安装满足 bar 对 blerg@1.x 的依赖,所以没有在 [B]下安装另一个副本。

Bar [B] 也依赖于 baz 和 asdf,所以它们安装在 bar 的 node_modules 文件夹中。 因为它依赖于 baz@2.x,所以它不能重复使用安装在父 node_modules 文件夹 [D]中的 baz@1.2.3,必须安装自己的副本 [C]

在条形下方,baz -> quux -> bar 依赖创建了一个循环。 但是,因为 bar 已经在 quux 的祖级 [B] 中,所以它不会将 bar 的另一个副本解压缩到该文件夹​​中。

foo -> baz [D] 下面,quux 的 [E] 文件夹树是空的,因为它对 bar 的依赖由安装在 [B] 的父文件夹副本满足。

有关安装位置的图形细分,请使用 npm ls

发布

发布后,npm 将在 node_modules 文件夹中查找。 如果有任何项目不在 bundledDependencies 数组中,则它们将不会包含在包 tarball 中。

这允许包维护者在本地安装他们所有的依赖(和开发依赖),但只重新发布那些在其他地方找不到的项目。 有关详细信息,请参阅 package.json

也可以看看

npm 中文网 - 粤ICP备13048890号