如何使用在node_modules本地安装的软件包?

如何在node.js使用本地版本的模块。 例如,在我的应用程序中,我安装了咖啡脚本:

 npm install coffee-script 

这将它安装在./node_modules ,并且coffee命令在./node_modules/.bin/coffee 。 当我在我的项目的主文件夹中有没有办法运行这个命令? 我想我正在寻找类似bundle exec东西。 基本上,我想指定一个与项目有关的每个人都应该使用的咖啡脚本的版本。

我知道我可以添加-g标志来全局安装它,所以咖啡在任何地方都能正常工作,但是如果我想为每个项目使用不同版本的咖啡,该怎么办?

推杆的问题

 ./node_modules/.bin 

进入你的PATH的是,它只有当你的工作目录是你的项目目录结构的根(即node_modules的位置)

独立于你的工作目录,你可以得到本地安装的二进制文件的path

 npm bin 

要执行本地安装的coffee二进制文件,无论您在项目目录层次结构中的哪个位置,都可以使用这个bash构造

 PATH=$(npm bin):$PATH coffee 

我把这个别名给npm-exec

 alias npm-exec='PATH=$(npm bin):$PATH' 

所以,现在我可以

 npm-exec coffee 

无论我在哪里,都要运行正确的咖啡副本

 $ pwd /Users/regular/project1 $ npm-exec which coffee /Users/regular/project1/node_modules/.bin/coffee $ cd lib/ $ npm-exec which coffee /Users/regular/project1/node_modules/.bin/coffee $ cd ~/project2 $ npm-exec which coffee /Users/regular/project2/node_modules/.bin/coffee 

使用npm bin命令获取项目的节点modules / bin目录

 $ $(npm bin)/<binary-name> [args] 

例如

 $ $(npm bin)/bower install 

使用npm run[-script] <script name>

使用npm将bin软件包安装到本地./node_modules目录后,修改package.json来添加,如下所示:

 $ npm install --save learnyounode $ edit packages.json >>> in packages.json ... "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "learnyounode": "learnyounode" }, ... $ npm run learnyounode 

如果npm install有一个–add-script选项,或者npm run不需要添加脚本块就可以工作,那将会很好。

更新:我不再推荐这种方法,既出于提到的安全原因,也不是至less新的npm bin命令。 下面的原始答案:

正如您发现的那样,任何本地安装的二进制文件都位于./node_modules/.bin 。 为了总是在这个目录中运行二进制文件,而不是全局可用的二进制文件(如果存在的话),我build议你./node_modules/.bin放在你的path中:

 export PATH="./node_modules/.bin:$PATH" 

如果你把它放在你的~/.profile ,那么coffee将永远是./node_modules/.bin/coffee ,否则/usr/local/bin/coffee (或者你正在安装节点模块的前缀)。

使用npm-run

自述文件:

NPM-运行

从node_modules查找并运行本地可执行文件

任何可用于npm生命周期脚本的可执行文件都可用于npm-run

用法

 $ npm install mocha # mocha installed in ./node_modules $ npm-run mocha test/* # uses locally installed mocha executable 

安装

 $ npm install -g npm-run 

你不必操纵$PATH了!

从npm@5.2.0开始 , npm提供了npx包,允许您从本地node_modules/.bin或中央caching运行命令。

只需运行:

 $ npx [options] <command>[@version] [command-arg]... 

默认情况下, npx将检查$PATH是否存在<command> ,或者在本地项目二进制文件中执行该命令。

<command>不在$PATH时调用npx <command>会自动从NPMregistry中为你安装一个名称为package的包,并调用它。 完成后,已安装的软件包将不会在您的全球任何地方,所以您不必长期担心污染。 您可以通过提供--no-install选项来防止此行为。

对于npm < 5.2.0 ,您可以通过运行以下命令来手动安装npx软件包:

 $ npm install -g npx 

PATH解决scheme的问题是,如果$(npm bin)被放置在你的.profile / .bashrc / etc目录中,那么它会被评估一次,永远被设置为path被首先评估的目录。如果改为修改当前path,每次运行脚本时,path都会增长。

为了解决这些问题,我创build了一个函数并使用它。 它不会修改您的环境,使用简单:

 function npm-exec { $(npm bin)/$@ } 

这可以像这样使用,而不需要对环境做任何改变:

 npm-exec r.js <args> 

如果您希望您的PATHvariables根据您当前的工作目录正确更新,请将其添加到.bashrc -eivaivalent(或定义PATH任何内容)的末尾:

 __OLD_PATH=$PATH function updatePATHForNPM() { export PATH=$(npm bin):$__OLD_PATH } function node-mode() { PROMPT_COMMAND=updatePATHForNPM } function node-mode-off() { unset PROMPT_COMMAND PATH=$__OLD_PATH } # Uncomment to enable node-mode by default: # node-mode 

这可能会在每次提交bash提示时增加一个很短的延迟(取决于项目的大小,很可能),所以默认情况下它是禁用的。

您可以通过分别运行node-modenode-mode-off来启用和禁用terminal。

对于Windows

将以下内容存储在名为npm-exec.bat的文件中,并将其添加到%PATH%

 @echo off set cmd="npm bin" FOR /F "tokens=*" %%i IN (' %cmd% ') DO SET modules=%%i "%modules%"\%* 

用法

那么你可以像npm-exec <command> <arg0> <arg1> ...一样使用它npm-exec <command> <arg0> <arg1> ...

例如

要执行安装在本地node_modules目录中的wdio,请执行wdio操作:

 npm-exec wdio wdio.conf.js 

即它将运行.\node_modules\.bin\wdio wdio.conf.js

您也可以使用direnv,并只在工作文件夹中更改$ PATHvariables。

 $ cat .envrc > export PATH=$(npm bin):$PATH 

将这个脚本添加到你的.bashrc 。 那么你可以打电话给coffee或任何地方。 这对你的笔记本电脑来说很方便,但是不要在你的服务器上使用它。

 DEFAULT_PATH=$PATH; add_local_node_modules_to_path(){ NODE_MODULES='./node_modules/.bin'; if [ -d $NODE_MODULES ]; then PATH=$DEFAULT_PATH:$NODE_MODULES; else PATH=$DEFAULT_PATH; fi } cd () { builtin cd "$@"; add_local_node_modules_to_path; } add_local_node_modules_to_path; 

注意 :这个脚本使用了别名的cd命令,并且在每次调用cd之后,它检查node_modules/.bin并将它添加到你的$PATH

注2 :可以将第三行改为NODE_MODULES=$(npm bin); 。 但是这会使cd命令太慢。

相同@regular的可接受的解决scheme,但鱼贝壳的味道

 if not contains (npm bin) $PATH set PATH (npm bin) $PATH end 

zxc就像nodejs的“bundle exec”一样。 它类似于使用PATH=$(npm bin):$PATH

 $ npm install -g zxc $ npm install gulp $ zxc which gulp /home/nathan/code/project1/node_modules/.bin/gulp 

我很想知道这是不是一个不安全/不好的想法,但是想一想,我在这里没有看到一个问题:

修改Linus的不安全的解决scheme,将其添加到最后,使用npm bin来查找目录,并使脚本仅在package.json存在于父级(为了速度)时调用npm bin ,这就是我想出的zsh

 find-up () { path=$(pwd) while [[ "$path" != "" && ! -e "$path/$1" ]]; do path=${path%/*} done echo "$path" } precmd() { if [ "$(find-up package.json)" != "" ]; then new_bin=$(npm bin) if [ "$NODE_MODULES_PATH" != "$new_bin" ]; then export PATH=${PATH%:$NODE_MODULES_PATH}:$new_bin export NODE_MODULES_PATH=$new_bin fi else if [ "$NODE_MODULES_PATH" != "" ]; then export PATH=${PATH%:$NODE_MODULES_PATH} export NODE_MODULES_PATH="" fi fi } 

对于bash ,可以使用$PROMPT_COMMANDvariables(我没有testing过这个,但是你有这个想法),而不是使用precmd钩子:

 __add-node-to-path() { if [ "$(find-up package.json)" != "" ]; then new_bin=$(npm bin) if [ "$NODE_MODULES_PATH" != "$new_bin" ]; then export PATH=${PATH%:$NODE_MODULES_PATH}:$new_bin export NODE_MODULES_PATH=$new_bin fi else if [ "$NODE_MODULES_PATH" != "" ]; then export PATH=${PATH%:$NODE_MODULES_PATH} export NODE_MODULES_PATH="" fi fi } export PROMPT_COMMAND="__add-node-to-path" 

我是一个Windows用户,这是我的工作:

 // First set some variable - ie replace is with "xo" D:\project\root> set xo="./node_modules/.bin/" // Next, work with it D:\project\root> %xo%/bower install 

祝你好运。

如果切换到纱线(Facebook的npm更换)是你的select,那么你可以打电话给:

  yarn yourCmd 

package.json中的脚本优先,如果没有find它,它将在./node_modules/.bin/文件夹中查找。

它也输出它运行的内容:

 $ yarn tsc yarn tsc v0.27.5 $ "/home/philipp/rate-pipeline/node_modules/.bin/tsc" 

所以你不必为package.json每个命令设置脚本。


如果您在package.json中的.scripts定义了一个脚本:

 "tsc": "tsc" // each command defined in the scripts will be executed from `./node_modules/.bin/` first 

yarn tsc相当于yarn run tscnpm run tsc

  yarn tsc yarn tsc v0.27.5 $ tsc 

我遇到了同样的问题,我不是特别喜欢使用别名(如常规的build议),如果你不喜欢他们,那么这里是另一个我使用的解决方法,你首先必须创build一个微小的可执行bash脚本,说setenv.sh

 #!/bin/sh # Add your local node_modules bin to the path export PATH="$(npm bin):$PATH" # execute the rest of the command exec "$@" 

然后你可以使用这个命令在你的本地/bin使用任何可执行文件:

 ./setenv.sh <command> ./setenv.sh 6to5-node server.js ./setenv.sh grunt 

如果你在package.json中使用scripts ,那么:

 ..., scripts: { 'start': './setenv.sh <command>' } 

对于Windows使用这个:

 /* cmd into "node_modules" folder */ "%CD%\.bin\grunt" --version 

如果你正在使用fish shell并且不想为了安全原因而添加到$path 。 我们可以添加下面的函数来运行本地节点可执行文件。

 ### run executables in node_module/.bin directory function n set -l npmbin (npm bin) set -l argvCount (count $argv) switch $argvCount case 0 echo please specify the local node executable as 1st argument case 1 # for one argument, we can eval directly eval $npmbin/$argv case '*' set --local executable $argv[1] # for 2 or more arguments we cannot append directly after the $npmbin/ since the fish will apply each array element after the the start string: $npmbin/arg1 $npmbin/arg2... # This is just how fish interoperate array. set --erase argv[1] eval $npmbin/$executable $argv end end 

现在你可以运行如下的东西:

n coffee

或更多的参数,如:

n browser-sync --version

请注意,如果您是bash用户,那么@ Bob9630答案是利用bash的$@ ,这在fishshell不可用。

在package.json中包含咖啡脚本和每个项目所需的特定版本,通常如下所示:

 "dependencies":{ "coffee-script": ">= 1.2.0" 

然后运行npm install在每个项目中安装依赖项。 这将安装咖啡脚本的指定版本,每个项目都可以在本地访问。