如何在node.js中使用一个模块的本地版本。例如,在我的应用程序中,我安装了coffee-script:

npm install coffee-script

这会将其安装在。/node_modules中,而coffee命令则安装在。/node_modules/.bin/coffee中。当我在项目的主文件夹中时,是否有一种方法可以运行此命令?我想我在寻找类似于捆绑执行者的东西。基本上,我想指定一个参与项目的每个人都应该使用的coffee-script版本。

我知道我可以添加-g标志来在全球范围内安装它,这样咖啡在任何地方都可以正常工作,但是如果我想在每个项目中使用不同版本的咖啡呢?


包中包括咖啡脚本。Json和每个项目所需的特定版本,通常如下所示:

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

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


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

正如您所发现的,任何本地安装的二进制文件都在./node_modules/.bin中。为了总是在这个目录下运行二进制文件,而不是全局可用的二进制文件,如果存在,我建议你把./node_modules/.bin放在你的路径的前面:

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

如果你把这个放在~/。配置文件,coffee将永远是。/node_modules/.bin/coffee(如果可用的话),否则是/usr/local/bin/coffee(或任何你安装节点模块的前缀)。


更新:正如Seyeong Jeong在他们的回答中指出的那样,从npm 5.2.0开始,你可以使用npx[命令],这更方便。

5.2.0之前版本的旧答案:

放置的问题

./node_modules/.bin

只有当你的当前工作目录是你的项目目录结构的根目录(即node_modules的位置)时,它才有效。

不管您的工作目录是什么,您都可以使用

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

如果你想让你的PATH变量根据你当前的工作目录正确地更新,把它添加到你的.bashrc等价文件的末尾(或者任何定义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-mode和node-mode-off来启用和禁用它。


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

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

e.g.

$ $(npm bin)/bower install

我遇到了同样的问题,我不特别喜欢使用别名(正如常规的建议),如果你也不喜欢它们,那么这里有另一个我使用的解决方案,你首先必须创建一个小的可执行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

如果你在包中使用脚本。json:

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

使用npm run[-script] <脚本名>

使用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不添加脚本块也能正常工作,那就太好了。


PATH解决方案有一个问题,如果$(npm bin)被放在你的.profile/。Bashrc /etc只计算一次,并且永远被设置到路径第一次计算所在的目录。如果您修改当前路径,那么每次运行脚本时,路径都会增长。

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

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

然后可以像这样使用,而不需要对环境进行任何更改:

npm-exec r.js <args>

相同的@常规的接受方案,但鱼壳味

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的不安全解决方案,将其添加到末尾,使用npm bin查找目录,并使脚本只在包时调用npm bin。json是存在于一个父(速度),这是我为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,不使用precmd钩子,你可以使用$PROMPT_COMMAND变量(我还没有测试过,但你知道的):

__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"

更新:如果你在最近的npm(版本>5.2)

你可以使用:

npx <command>

NPX在node_modules的.bin目录下查找命令

旧的回答:

对于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>…

例如

要执行本地node_modules目录下安装的wdio,请执行:

npm-exec wdio wdio.conf.js

例如,它将运行。\node_modules\.bin\wdio wdio.conf.js


使用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

您也可以使用direnv并仅在您的工作文件夹中更改$PATH变量。

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

将此脚本添加到您的.bashrc。然后你可以叫咖啡或当地的任何东西。这对你的笔记本电脑很方便,但不要在你的服务器上使用。

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命令太慢。


我是一个Windows用户,这对我来说是有效的:

// First set some variable - i.e. replace is with "xo"
D:\project\root> set xo="./node_modules/.bin/"

// Next, work with it
D:\project\root> %xo%/bower install

祝你好运。


对于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咖啡

或者更多像这样的论点:

N浏览器同步——版本

注意,如果您是bash用户,则可以使用bash的$@来回答@ bob9630,这在fishshell中是不可用的。


你不必再操纵$PATH了!

从npm@5.2.0, npm附带了npx包,它可以让你从本地node_modules/.bin或中央缓存运行命令。

简单地运行:

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

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

当<命令>不在$PATH中时调用npx <命令>将自动从NPM注册表中为你安装一个带有该名称的包,并调用它。当它完成时,安装的包将不会在你的全局包的任何地方,所以你不必担心长期的污染。你可以通过提供——no-install选项来防止这种行为。

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

$ npm install -g npx

如果你想保留npm,那么npx应该做你所需要的。


如果切换到yarn (facebook的npm替代品)是你的一个选择,那么你可以调用:

 yarn yourCmd

包中的脚本。Json将优先,如果没有找到,它将在./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

纱线TSC相当于纱线运行TSC或NPM运行TSC:

 yarn tsc
 yarn tsc v0.27.5
 $ tsc

我不喜欢依赖shell别名或其他包。

向包的脚本部分添加简单的一行。Json,你可以运行本地NPM命令像

pm网络包装

package.json

{
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "webpack": "webpack"
  },
  "devDependencies": {
    "webpack": "^4.1.1",
    "webpack-cli": "^2.0.11"
  }
}

我一直使用与@guneysus相同的方法来解决这个问题,即在包中创建一个脚本。Json文件,并使用它运行NPM run script-name。

然而,最近几个月我一直在使用npx,我很喜欢它。

例如,我下载了一个Angular项目,但我不想全局安装Angular CLI。所以,在安装了npx之后,不用使用angular cli的全局命令(如果我已经安装了它),就像这样:

ng serve

我可以从控制台这样做:

npx ng serve

这是我写的一篇关于NPX的文章,更深入地讨论了它。


TL;DR:使用npm exec与npm@>=7。


在其他回答中提到的npx命令已经在npm@7中完全重写,该命令默认与node@15一起发布,可以安装在node@>=10上。这个实现现在等于新引入的npm exec命令,它类似于之前的npx命令实现,但不等于。

一个不同之处在于,当一个依赖项还没有安装时,它总是交互式地询问是否应该下载它(也可以用参数——yes或——no来覆盖)。

这里有一个npm exec的例子。双破折号(——)将npm exec参数与实际的命令参数分开:

npm exec --no -- jest --coverage

请参见更新后的npm exec官方文档。


我提出了一个我已经开发的新解决方案(05/2021)

您可以使用lpx https://www.npmjs.com/package/lpx来

运行本地node_modules/.bin文件夹中的二进制文件 在工作空间的任何地方运行工作空间根目录的node_modules/.bin中的二进制文件

如果在本地找不到二进制文件,LPX不会下载任何包(即不像npx)

例子: LPX TSC -b -w将与本地typescript包一起运行TSC -b -w