Как использовать пакет, установленный локально в узловых модулях?


как использовать локальную версию модуля в node.js. Например, в моем приложении я установил coffee-script:

npm install coffee-script

это устанавливает его в ./node_modules и команда кофе находится в ./node_modules/.bin/coffee. Есть ли способ запустить эту команду, когда я нахожусь в главной папке моего проекта? Я думаю, что я ищу что-то похожее на bundle exec в упаковщик. В принципе, я хотел бы указать версию coffee-script, которую должны использовать все участники проекта.

Я знаю, что могу добавить -g флаг, чтобы установить его глобально, так что кофе отлично работает в любом месте, но что делать, если я хотел бы иметь разные версии кофе для каждого проекта?

22 354

22 ответа:

проблема с вводом

./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

Nice example

вы не должны манипулировать на $PATH, или в локальных двоичных файлах проекта, и выполните это.

вызов npx <command>, когда <command> уже нет $PATH автоматически установит пакет с этим именем из реестра NPM для вас и вызовет его. Когда это будет сделано, установленный пакет не будет нигде в ваших глобалах, поэтому вам не придется беспокоиться о загрязнении в долгосрочной перспективе. Вы можете предотвратить такое поведение, предоставив .

на npm < 5.2.0, вы можете установить npx пакета вручную, выполнив следующую команду:

$ npm install -g npx

использовать npm bin команда для получения каталога модулей узлов / bin вашего проекта

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

например

$ $(npm bin)/bower install

использовать npm run[-script] <script name>

после использования npm для установки пакета bin на локальный

использовать npm-run.

из readme:

npm-run

найти и запустить локальные исполняемые файлы из папки 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

обновление: Я больше не рекомендую этот метод, как по упомянутым причинам безопасности, так и не в последнюю очередь новее

решение пути имеет проблему, что если $(npm bin) помещается в ваш .профиль./bashrc / etc он оценивается один раз и навсегда устанавливается в любой каталог, в котором был впервые оценен путь. Если вместо этого вы измените текущий путь, то каждый раз, когда вы запускаете скрипт, ваш путь будет расти.

чтобы обойти эти проблемы, я создаю функцию и использовал это. Он не изменяет вашу среду и прост в использовании:

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

Это может быть использовано, как это без внесение любых изменений в вашу среду:

npm-exec r.js <args>

если вы хотите сохранить НПМ, затем npx должны делать то, что вам нужно.


если переключение на yarn (замена npm на facebook) является вариантом для вас, то вы можете позвонить:

 yarn yourCmd

скрипты внутри упаковки.json будет иметь приоритет, если он не найден, он будет искать внутри .

он также выводит то, что он побежал:

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

таким образом, вам не нужно настраивать скрипты для каждой команды в вашем package.json.


если бы у вас был скрипт, определенный в .scripts внутри package.json:

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

yarn tsc было бы эквивалентно yarn run tsc или npm run tsc:

 yarn tsc
 yarn tsc v0.27.5
 $ tsc

если вы хотите, чтобы ваша переменная пути правильно обновлялась на основе вашего текущего рабочего каталога, добавьте это в конец вашего .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, соответственно.

Я предпочитаю не полагаться на псевдонимы оболочки или другой пакет.

добавление простой строки в вашего package.json, вы можете запускать локальные команды npm, такие как

npm run webpack

.json

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

zxc похоже на" bundle exec " для nodejs. Это похоже на использование PATH=$(npm bin):$PATH:

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

такое же @регулярн принятое решение, но вкус раковины Рыб

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

Для 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> ...

для выполнения wdio установленный в локальном каталоге node_modules, выполните:

npm-exec wdio wdio.conf.js

т. е. он будет работать .\node_modules\.bin\wdio wdio.conf.js

вы также можете использовать direnv и изменить переменную $PATH только в своей рабочей папке.

$ 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 он проверяет node_modules/.bin и добавить его в свой $PATH.

примечание2: вы можете изменить третью строку с NODE_MODULES=$(npm bin);. Но что бы сделать cd команда слишком медленная.

для Windows используйте это:

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

я столкнулся с той же проблемой и мне не особо нравится использовать псевдонимы (как обычныйпредлагается), и если вам они тоже не нравятся, то вот еще один обходной путь, который я использую, вам сначала нужно создать крошечный исполняемый скрипт 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

если вы используете scripts в пакет.json тогда:

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

Я хотел бы знать, если это небезопасно/плохая идея, но подумав немного, я не вижу здесь проблемы:

изменение небезопасного решения Линуса, чтобы добавить его в конец, используя npm bin чтобы найти каталог, и сделать скрипт только вызов npm bin когда a package.json присутствует в родительской (для скорости), это то, что я придумал для zsh:

find-up () {
  path=$(pwd)
  while [[ "$path" != "" && ! -e "$path/" ]]; 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"

Я 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

Удачи.

в случае, если вы используете 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's $@, который не доступен в fishshell.

Я всегда использовал тот же подход, что и @guneysus для решения этой проблемы, которая заключается в создании скрипта в пакете.JSON-файл и использовать его под управлением npm run script-name.

однако, в последние месяцы я использую npx и мне это нравится.

например, я загрузил угловой проект, и я не хотел устанавливать угловой CLI глобально. Итак, с установленным npx вместо использования команды global angular cli (если бы я ее установил), например это:

ng serve

Я могу сделать это из консоли:

npx ng serve

включить кофе-скрипт в пакет.json с конкретной версией, необходимой в каждом проекте, как правило, так:

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

затем запустите npm install для установки зависимостей в каждом проекте. Это позволит установить указанную версию coffee-script, которая будет доступна локально для каждого проекта.