Как использовать пакет, установленный локально в node_modules?

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

npm install coffee-script

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

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

25 ответов

Решение

ОБНОВЛЕНИЕ: Как Seyeong Jeong указывает в своем ответе ниже, начиная с npm 5.2.0 вы можете использовать npx [command], что более удобно.

СТАРЫЙ ОТВЕТ для версий до 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 больше!

С npm@5.2.0npm поставляется с npx пакет, который позволяет запускать команды из локального node_modules/.bin или из центрального кэша.

Просто запустите:

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

По умолчанию, npx проверим ли <command> существует в $PATHили в локальных двоичных файлах проекта, и выполните это.

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

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

$ npm install -g npx

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

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

например

$ $(npm bin)/bower install

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

После использования npm для установки пакета bin на ваш локальный ./node_modules каталог, изменить package.json добавить <script name> как это:

$ 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 работал бы без добавления в блок scripts.

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

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

Как вы узнали, все локально установленные двоичные файлы находятся в ./node_modules/.bin, Чтобы всегда запускать двоичные файлы в этом каталоге, а не глобально доступные двоичные файлы, если они есть, я предлагаю вам поставить ./node_modules/.bin Первый на вашем пути:

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

Если вы положите это в свой ~/.profile, coffee всегда будет ./node_modules/.bin/coffee если доступно, в противном случае /usr/local/bin/coffee (или любой другой префикс, под которым вы устанавливаете модули узлов).

Использование npm-run,

Из readme:

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

TL;DR: использовать с npm@>=7.


Команда, которая упоминалась в других ответах, была полностью переписана в npm@7 который по умолчанию поставляется с node@15 и может быть установлен на node@>=10. Реализация теперь равна недавно введенной команде, которая похожа, но не равна предыдущей. npx реализация команды.

Одно из отличий заключается, например, в том, что он всегда в интерактивном режиме спрашивает, следует ли загружать зависимость, если она еще не установлена ​​(также может быть перезаписана параметрами --yes или же --no).

Вот пример для. Двойные тире ( --) отделяет параметры от фактических параметров команды:

      npm exec --no -- jest --coverage

См. Также обновленную официальную документацию по <tcode id="4336955"></tcode>.

Если вы хотите сохранить npm, тогда npx должен делать то, что вам нужно.


Если вам подходит переход на пряжу (замена npm на Facebook), вы можете позвонить:

 yarn yourCmd

скрипты в package.json будут иметь приоритет, если ничего не найдено, они будут смотреть внутрь ./node_modules/.bin/ папка.

Это также выводит то, что это бежало:

$ 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

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

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

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

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

npm-exec r.js <args>

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

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

npm run webpack

package.json

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

Если вы хотите, чтобы ваша переменная 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соответственно.

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

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

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

ng serve

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

npx ng serve

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

То же решение @regular, но вкус рыбных раковин

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

Ответ 2023:

Старое решение:$(npm bin)/package

Правильный ответ раньше был$(npm bin)/package-nameпока npm не удалил его в версии 9 (около августа 2022 г.).

Новое решениеnpm exec -- package

Новое решение, которое рекомендует Node, — это илиnpm execкоторые немного отличаются . Я пробовал следовать этому документу, но единственный формат, который мне идеально подходил, былnpm exec -- package-name -x ...который будет правильно передавать параметры вpackage-name.

Как ни странно, используяnpx(с или без--) предлагал мне установитьrunnpm, который является неактуальным пакетом 8-летней давности !

ТЛ;ДР

Обновление с узла 16 до узла 20, в моемpackage.jsonмне нужно было заменить

      {
        "build-prod": "npm run clean && $(npm bin)/npm-run-all -s _build:*"
}

с

      {
        "build-prod": "npm run clean && npm exec -- npm-run-all -s _build:*"
}

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

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

Добавьте этот скрипт в свой .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 Команда слишком медленная.

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

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

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

Изменение небезопасного решения Линуса, чтобы добавить его в конец, используя npm bin найти каталог и сделать скрипт только по вызову npm bin когда package.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"

Если вы используете 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,

Я столкнулся с той же проблемой, и мне не очень нравятся псевдонимы (как это regular), и если они вам не нравятся, вот еще один обходной путь, который я использую, сначала вы должны создать крошечный исполняемый скрипт bash, скажи сетенв.ш

#!/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 в package.json тогда:

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

Я 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

Удачи.

I propose a new solution (05/2021)

You can use lpx https://www.npmjs.com/package/lpx to

  • run a binary found in the local node_modules/.bin folder
  • run a binary found in the node_modules/.bin of a workspace root from anywhere in the workspace

lpx does not download any package if the binary is not found locally (ie not like npx)

Example : lpx tsc -b -w will run tsc -b -w with the local typescript package

Включите coffee-script в package.json с конкретной версией, необходимой для каждого проекта, как правило, так:

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

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

Другие вопросы по тегам