npm ls -g
npm root -g
npm bin -g
npm link
:全局安装未发布的包npm link
:在本地安装全局链接的包npm link
:取消链接npx
:在 npm 包中运行 bin 脚本,而无需安装它们package.json
属性 "bin"
允许 npm 包指定它提供的 shell 脚本(有关更多信息,请参阅 §14 “创建跨平台 shell 脚本”)。如果我们安装了这样一个包,Node.js 会确保我们可以从命令行访问这些 shell 脚本(所谓的*bin 脚本*)。在本章中,我们将探讨两种安装带有 bin 脚本的包的方法。
本地安装带有 bin 脚本的包意味着将其作为依赖项安装在包中。这些脚本只能在该包中访问。
全局安装带有 bin 脚本的包意味着将其安装在“全局位置”,以便所有地方都可以访问这些脚本 - 对于当前用户或系统的 所有用户(取决于 npm 的设置方式)。
我们将探讨所有这些含义,以及如何在安装 bin 脚本后运行它们。
包 cowsay
具有以下 package.json
属性
"bin": {
"cowsay": "./cli.js",
"cowthink": "./cli.js"
},
要全局安装此包,我们使用 npm install -g
npm install -g cowsay
注意:在 Unix 上,我们可能必须使用 sudo
(我们很快就会学习如何避免这种情况)
sudo npm install -g cowsay
之后,我们可以在命令行中使用 cowsay
和 cowthink
命令。
请注意,只有 bin 脚本是全局可用的。当 Node.js 在 node_modules
目录中查找裸模块说明符时,会忽略这些包。
npm ls -g
我们可以检查哪些包是全局安装的,以及安装在哪里
% npm ls -g
/usr/local/lib
├── [email protected]
├── [email protected]
└── [email protected]
在 Windows 上,安装路径为 %AppData%\npm
,例如
>echo %AppData%\npm
C:\Users\jane\AppData\Roaming\npm
npm root -g
macOS 上的结果
% npm root -g
/usr/local/lib/node_modules
Windows 上的结果
>npm root -g
C:\Users\jane\AppData\Roaming\npm\node_modules
npm bin -g
npm bin -g
告诉我们 npm 在哪里全局安装 shell 脚本。它还确保该目录在 shell PATH 中可用。
macOS 上的结果
% npm bin -g
/usr/local/bin
% which cowsay
/usr/local/bin/cowsay
Windows 命令提示符上的结果
>npm bin -g
C:\Users\jane\AppData\Roaming\npm
>where cowsay
C:\Users\jane\AppData\Roaming\npm\cowsay
C:\Users\jane\AppData\Roaming\npm\cowsay.cmd
没有文件扩展名的可执行文件 cowsay
适用于基于 Unix 的 Windows 环境,例如 Cygwin、MinGW 和 MSYS。
Windows PowerShell 为 gcm cowsay
返回此路径
C:\Users\jane\AppData\Roaming\npm\cowsay.ps1
npm 的*安装前缀*决定了全局安装包和 bin 脚本的位置。
这是 macOS 上的安装前缀
% npm config get prefix
/usr/local
因此
/usr/local/lib/node_modules
中/usr/local/bin
中这是 Windows 上的安装前缀
>npm config get prefix
C:\Users\jane\AppData\Roaming\npm
因此
C:\Users\jane\AppData\Roaming\npm\node_modules
中C:\Users\jane\AppData\Roaming\npm
中在本节中,我们将研究两种更改全局安装包位置的方法
更改全局安装包位置的一种方法是更改 npm 安装前缀。
Unix
mkdir ~/npm-global
npm config set prefix '~/npm-global'
Windows 命令提示符
mkdir "%UserProfile%\npm-global"
npm config set prefix "%UserProfile%\npm-global"
Windows PowerShell
mkdir "$env:UserProfile\npm-global"
npm config set prefix "$env:UserProfile\npm-global"
配置数据将保存到主目录中的 .npmrc
文件中。
从现在开始,全局安装将添加到我们刚刚指定的目录中。
之后,我们仍然需要将 npm bin -g
目录添加到我们的 shell PATH 中,以便我们的 shell 能够找到我们全局安装的 bin 脚本。
**更改 npm 前缀的缺点:** 如果我们告诉 npm 升级自身,它现在也会安装在新位置。
Node.js 版本管理器允许我们同时安装多个版本的 Node.js,并在它们之间切换。流行的版本管理器包括
要*本地*安装 npm 注册表包(例如 cowsay
)(到一个包中),我们执行以下操作
cd my-package/
npm install cowsay
这会将以下数据添加到 package.json
中
"dependencies": {
"cowsay": "^1.5.0",
···
}
此外,该包将下载到以下目录中
my-package/node_modules/cowsay/
在 Unix 上,npm 为 bin 脚本添加了以下符号链接
my-package/node_modules/.bin/cowsay -> ../cowsay/cli.js
my-package/node_modules/.bin/cowthink -> ../cowsay/cli.js
在 Windows 上,npm 将这些文件添加到 my-package\node_modules\.bin\
中
cowsay
cowsay.cmd
cowsay.ps1
cowthink
cowthink.cmd
cowthink.ps1
没有扩展名的文件是用于基于 Unix 的 Windows 环境(例如 Cygwin、MinGW 和 MSYS)的脚本。
npm bin
告诉我们本地安装的 bin 脚本的位置 - 例如
% npm bin
/Users/john/my-package/node_modules/.bin
注意:在本地,包始终安装在 package.json
文件旁边的 node_modules
目录中。如果当前目录中不存在后者,npm 会在祖先目录中搜索它,并将包安装在那里。要检查 npm 会在本地安装包的位置,我们可以使用命令 npm root
- 例如(Unix)
% cd $HOME
% npm root
/Users/john/node_modules
John 的主目录中没有 package.json
,但 npm 无法在祖先目录中安装任何内容,这就是 npm root
显示此目录的原因。在当前位置本地安装包将导致创建 package.json
并照常进行安装。
(本小节中的所有命令都在目录 my-package
中执行。)
我们可以从 shell 中按如下方式运行 cowsay
./node_modules/.bin/cowsay Hello
在 Unix 上,我们可以设置一个助手
alias npm-exec='PATH=$(npm bin):$PATH'
然后以下命令将起作用
npm-exec cowsay Hello
我们还可以向 package.json
添加一个包脚本
{
···
"scripts": {
"cowsay": "cowsay"
},
···
}
现在我们可以在 shell 中执行此命令
npm run cowsay Hello
之所以可行,是因为 npm 在 Unix 上临时将以下条目添加到 $PATH
中
/Users/john/my-package/node_modules/.bin
/Users/john/node_modules/.bin
/Users/node_modules/.bin
/node_modules/.bin
在 Windows 上,类似的条目将添加到 %Path%
或 $env:Path
中
C:\Users\jane\my-package\node_modules\.bin
C:\Users\jane\node_modules\.bin
C:\Users\node_modules\.bin
C:\node_modules\.bin
以下命令列出了包脚本运行时存在的环境变量及其值
npm run env
在包内部,可以使用 npx 访问 bin 脚本
npx cowsay Hello
npx cowthink Hello
稍后将详细介绍 npx。
有时,我们有一个尚未发布或永远不会发布的包,并且希望安装它。
npm link
:全局安装未发布的包假设我们有一个名为 @my-scope/unpublished-package
的未发布包,它存储在目录 /tmp/unpublished-package/
中。我们可以通过以下方式使其全局可用
cd /tmp/unpublished-package/
npm link
如果我们这样做
npm 会向全局 node_modules
(由 npm root -g
返回)添加一个符号链接 - 例如
/usr/local/lib/node_modules/@my-scope/unpublished-package
-> ../../../../../tmp/unpublished-package
在 Unix 上,npm 还会从全局 bin 目录(由 npm bin -g
返回)向每个 bin 脚本添加一个符号链接。该链接不是直接链接,而是通过全局 node_modules
目录
/usr/local/bin/my-command
-> ../lib/node_modules/@my-scope/unpublished-package/src/my-command.js
在 Windows 上,它会添加通常的 3 个脚本(它们通过全局 node_modules
中的相对路径引用链接的包)
C:\Users\jane\AppData\Roaming\npm\my-command
C:\Users\jane\AppData\Roaming\npm\my-command.cmd
C:\Users\jane\AppData\Roaming\npm\my-command.ps1
由于链接包的引用方式,对其进行的任何更改都将立即生效。更改时无需重新链接。
要检查全局安装是否成功,我们可以使用 npm ls -g
列出所有全局安装的包。
npm link
:在本地安装全局链接的包在全局安装了未发布的包之后(请参阅上一小节),我们可以选择将其本地安装在我们的一台机器上
cd /tmp/other-package/
npm link @my-scope/unpublished-package
这将创建以下链接
/tmp/other-package/node_modules/@my-scope/unpublished-package
-> ../../../unpublished-package
默认情况下,未发布的包不会作为依赖项添加到 package.json
中。其背后的理由是,npm link
通常用于临时使用注册表包的未发布版本 - 这不应该出现在依赖项中。
npm link
:取消链接取消本地链接
cd /tmp/other-package/
npm uninstall @my-scope/unpublished-package
取消全局链接
cd /tmp/unpublished-package/
npm uninstall -g
本地安装未发布包的另一种方法是使用 npm install
并通过本地路径(而不是包名称)引用它
cd /tmp/other-package/
npm install ../unpublished-package
这有两个效果。
首先,将创建以下符号链接
/tmp/other-package/node_modules/@my-scope/unpublished-package
-> ../../../unpublished-package
其次,将依赖项添加到 package.json
中
"dependencies": {
"@my-scope/unpublished-package": "file:../unpublished-package",
···
}
这种安装未发布包的方法也适用于全局安装
cd /tmp/unpublished-package/
npm install -g .
my-package/
。它们将被复制到 my-package/.yalc
目录中,并且 file:
或 link:
依赖项将被添加到 package.json
中。relative-deps
支持 package.json
中的 "relativeDependencies"
,如果它们存在,则会覆盖正常的依赖项。与 npm link
和本地路径安装相比
relative-deps
还有助于保持本地安装的相对依赖项及其原始依赖项同步。
npx link
是 npm link
的更安全版本,它不需要全局安装,以及其他优点。npx
:在 npm 包中运行 bin 脚本,而无需安装它们npx 是一个用于运行 bin 脚本的 shell 命令,它与 npm 捆绑在一起。
它最常见的用法是
npx <package-name> arg1 arg2 ...
此命令在 npx 缓存中安装名为 package-name
的包,并运行与包名称相同的 bin 脚本 - 例如
npx cowsay Hello
这意味着我们可以在不先安装 bin 脚本的情况下运行它们。npx 最适合一次性调用 bin 脚本 - 例如,许多框架都提供用于设置新项目的 bin 脚本,而这些脚本通常是通过 npx 运行的。
npx 首次使用某个包后,该包将在其缓存中可用,后续调用将快得多。但是,我们无法确定包在缓存中保留的时间。因此,npx 不能替代全局或本地安装 bin 脚本。
如果包附带的 bin 脚本的名称与其包名称不同,我们可以像这样访问它们
npx --package=<package-name> <bin-script> arg1 arg2 ...
例如
npx --package=cowsay cowthink Hello
npx 的缓存位于哪里?
在 Unix 上,我们可以通过以下命令找到它
npx --package=cowsay node -p \
"process.env.PATH.split(':').find(p => p.includes('_npx'))"
这将返回一个类似于此的路径
/Users/john/.npm/_npx/8f497369b2d6166e/node_modules/.bin
在 Windows 上,我们可以使用(一行分成两行)
npx --package=cowsay node -p
"process.env.Path.split(';').find(p => p.includes('_npx'))"
这将返回一个类似于此的路径(单个路径分成两行)
C:\Users\jane\AppData\Local\npm-cache\_npx\
8f497369b2d6166e\node_modules\.bin
请注意,npx 的缓存与 npm 用于安装模块的缓存不同
$HOME/.npm/_cacache/
$HOME/.npm/_npx/
$env:UserProfile\AppData\Local\npm-cache\_npx\
$env:UserProfile\AppData\Local\npm-cache\_cacache\
可以通过以下方式确定两个缓存的父目录
npm config get cache
有关 npm 缓存的更多信息,请参阅npm 文档。
与 npx 缓存不同,数据永远不会从 npm 缓存中删除,只会添加。我们可以在 Unix 上按如下方式检查其大小
du -sh $(npm config get cache)/_cacache/
在 Windows PowerShell 上
DiskUsage /d:0 "$(npm config get cache)\_cacache"