配置 npm
Last updated
Last updated
要从 public npm registry 安装和发布 packages,就必须安装 Node.js 和 npm 命令行工具。强烈建议使用 Node version manager 来安装 Node.js and npm,而不建议用 Node installer(因为它会把 npm 安装在一个具有 local 权限的目录里,这会导致 permissions errors 当我们全局运行 npm 包时)。
Node version manager:
OSX 和 Linux
Windows
nodist
nvm-windows
介绍 npm 使用的 folder structures。
npm 会在我们的电脑上放各种东西。当然,这正是它的工作。
local 安装(默认):会安装在 ./node_modules
global 安装(-g
):会安装在 prefix
配置的文件夹下
prefix
配置默认是 node 安装的位置
大多数系统,/usr/local
Windows,%AppData%\npm
Unix,它是上一级(one level up),因为 node 通常安装在 {prefix}/bin/node
而不是 {prefix}/node.exe
若 prefix
没设置,则就用当前 package 或者当前工作目录的根目录
若想 require()
使用,就 local 安装。若想在 command line 里使用,就 global 安装。若想同时使用,就在两个地方都安装,或者使用 npm link
。
packages 或
node modules
./node_modules
Unix 系统 {prefix}/lib/node_modules/
Windows 系统 {prefix}/node_modules/
可执行文件 be linked to
./node_modules/.bin/
Unix 系统 {prefix}/bin/
Windows 系统 {prefix}/
操作手册 be linked to
不安装
{prefix}/share/man
cache 文件
Posix ~/.npm
Windows %AppData%/npm-cache
临时文件
默认是环境变量 TMPDIR
, TMP
, TEMP
Unix /tmp
Windows c:\windows\temp
补充说明:
packages
scoped packages 的安装位置相同,只是它们又被分进了子目录
若是 local 安装的
可以使用 require("packagename")
去 load 它的 main module
使用 require("packagename/lib/path/to/sub/module")
去 load 其它 modules
可执行文件
对于 local 安装的,就能通过 npm run script 了
cache 文件
其路径可以由 cache
config 参数控制的
详见 npm cache
临时文件
其路径可以由 tmp
config 参数配置控制
每次 run program 时,临时文件都会在此根目录下指定一个唯一的文件夹,并在成功退出时被删除
prefix
补充当 local 安装时,npm 首先尝试找到合适的 prefix
folder。这样的话,即便我们碰巧 cd
进入了其它目录,npm install xxx
也会安装到合理的根目录中。
从 $PWD
开始,npm 将遍历 folder tree 以检查包含 package.json
文件或 node_modules
文件夹的 folder。
如果找到了,那它就被视为有效的 current directory,以运行 npm commands
这个逻辑受 git 的 .git-folder
的查找逻辑的启发。
如果没有找到 package root,则使用 current folder。
当运行 npm install foo@1.2.3
时
package 被 loaded 到 cache 中,然后 unpacked 到 ./node_modules/foo
。
接着,所有 foo 的依赖都被类似地 unpacked 到 ./node_modules/foo/node_modules/..
所有 bin 文件都 symlinked(符号链接)到 ./node_modules/.bin/
以便在运行 npm scripts 时可以找到它们。
对于 global 安装,packages 的安装方式大致相同,只是使用的文件夹不同。
cycles, conflicts 和 folder parsimony(简约)
cycles 是使用 node 的 module system 的属性来处理的,它会在目录中查找 node_modules
文件夹。所以,在每个阶段,如果某个 package 已经安装在了其祖先的 node_modules
文件夹中,那么它就不在当前位置安装了。
比如 foo -> bar -> baz
,如果再加一个 baz -> bar
,就不用将 bar
的另一个副本再放到 .../baz/node_modules/
里了,因为当 baz 调用 require("bar")
时会从 foo/node_modules/bar
里获得安装的副本。
这种 shortcut(快捷方式)只使用在多个嵌套的 node_modules
文件夹中需要安装 exact same version 的 package 时。当 a 的版本不一样时还是有可能出现 a/node_modules/b/node_modules/a
的。然而,如果不多次重复 exact same package,将始终 prevent(阻止/避免)无限 regress(倒退)。
还可以做个优化,就是在尽可能高的级别下安装 dependencies,在 localized "target" folder (hoisting, 提升)。从版本 3 开始,npm 默认 hoist(提升)dependencies。
比如如下 dependency graph:
第一:先处理第一层的依赖,即 foo 的依赖项
如下:
第二:再依次处理第二层的依赖
对于 blerg@1.2.5
,它没有依赖项。可以考虑 hoist 了,但因为其直接父已经是 root 了所以忽略
对于 bar@1.2.3
,它有三个依赖项
blerg@1.x
不用安了,因为其祖先已经有了,且版本匹配
baz@2.x
需要安,因为它和祖先的 baz@1.2.3
版本不匹配
asdf@*
需要安
对于 baz@1.2.3
,它有一个依赖项
quux@3.x
需要安
结果如下:
第三:再依次处理第三次依赖
bar@1.2.3 -> baz@2.x
,它有一个依赖
quux@3.x
不用安,因为祖先里已经有了
此时 bar@1.2.3 -> baz@2.x
是个叶子节点,但因为 root 下已经有另外一个版本的了所以不提升
bar@1.2.3 -> asdf@*
,它没有依赖。可以考虑 hoist,将其提升到 root
baz@1.2.3 -> quux@3.x
,它有一个依赖
bar@1.2.3
不用安,因为祖先里已经有了
此时 baz@1.2.3 -> quux@3.x
是个叶子节点,所以提升到 root
结果如下:
所以,最终的 folder structure 如上,我们把所有 dependencies 都 hoist 到尽可能高的级别。当然,真实项目里的版本都是符合条件的明确版本。
我们可以使用 npm ls
命令查看安装的 graphical breakdown(细分)。
一旦发布,npm 将会在 node_modules
文件夹中查找。只要是不在 bundleDependencies
数组中的 items,就不会被包含在 package tarball(压缩包)中。
这允许 package 维护者在本地安装他们所有的 dependencies(和 dev dependencies),但只 re-publish 那些在别处找不到的 items。相关详情可查阅 package.json。
.npmrc
npm 配置文件。npm 从 command line, environment variables 和 npmrc
files 获取它的 config settings。
四个相关文件是:
每个项目的配置文件 /path/to/my/project/.npmrc
每个用户的配置文件 ~/.npmrc
全局配置文件 $PREFIX/etc/npmrc
npm 内置配置文件 /path/to/npm/npmrc
npm config
命令可用来更新和编辑 user 和 global npmrc files 的内容。
所有的 npm 配置文件都是 ini 格式的 key = value
参数对列表。注释是以 ;
或 #
开头的行。
package.json
package.json
必须是实际的 JSON,而不仅仅是一个 JavaScript 对象字面量。
package-lock.json
当 npm 修改 node_modules
树或修改 package.json
时,就会自动生成 package-lock.json
。package-lock.json
描述了生成的 exact tree,以便后续的 install 能生成相同的树,而不管中间 dependency 的更新。
package-lock.json
应该提交到 source repository,目的有:
确保后续的 install 能生成完全相同的依赖关系
不用提交 node_modules
目录本身
提高 tree changes 的可见性,通过可读的 source control diffs
优化安装过程,因为 npm 可以跳过重复的 metadata resolution
从 npm v7 开始,lockfiles 包含了足够的信息以获取 package tree 的完整 picture,减少读取 package.json
文件的需要,允许显著的性能提升
为了避免重复处理 node_modules
文件夹,从 npm v7 开始使用一个 hidden lockfile node_modules/.package-lock.json
。它包含 tree 的相关信息,用于代替读取整个 node_modules
hierarchy(层次结构),前提是满足以下条件:
它引用的所有 package folders 都存在于 node_modules
层次结构中
不存在 package folders 是在 node_modules
层次结构中却没在 lockfile 中列出
file 的修改时间至少和其引用的所有 package folders 一样新
npm 的旧版本会忽略该 hidden lockfile。
npm-shrinkwrap.json
可发布的 lockfile(锁文件)。
该文件是由 npm shrinkwrap
命令创建的。它等价于 package-lock.json
,不同的是 npm-shrinkwrap.json
可能会在发布 package 时包含。
package-lock.json
vs npm-shrinkwrap.json
相同点:格式相同,在项目的根目录下发挥着相似的功能
不同点:
package-lock.json
不能发布,并且在项目的根目录以外的任何地方该文件都会被忽略
npm-shrinkwrap.json
允许发布,并且从 point 定义 dependency tree。除非部署 CLI 工具或以其它方式使用发布过程来生成 production packages,否则不建议这样做
如果 package 根目录中同时有这两个文件,那么 npm-shrinkwrap.json
会优先于 package-lock.json
文件。
更多信息详见 。
这里介绍的许多行为都受 配置设置的影响。